Use textfield input to get a value output - variables

I have made a simple textfield with a number keyboard.
The user is to put in a number (to make it simple I have set the number to sum=5).
If input is = sum, the text 'correct answer' will be printed on the screen. If the user input !=sum, the returned text will be 'wrong answer'.
To test if I actually got the numbers right I have a testprint, which functions correct.
My problem is how to transform this print output to text (so that it will show as text in the app).
I have been thinking about validating and form, but since I actually already get the correct answer printed, it shows I already get the values correct. Right?
I have tried a ton of things, but nothing has worked so far, so any help is appreciated. Thank you.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Textfields2',
home: MyHomeScreen(),
);
}
}
class MyHomeScreen extends StatefulWidget {
#override
_MyHomeScreenState createState() => _MyHomeScreenState();
}
class _MyHomeScreenState extends State<MyHomeScreen> {
final int sum = 5;
String output;
String enterAnswer;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: '?'),
onChanged: (val) {
enterAnswer = val;
},
),
RaisedButton(
child: Text('Submit Answer'),
onPressed: () {
if (enterAnswer.isNotEmpty) {
if (enterAnswer == sum.toString()) {
print('Correct'); //INTO TEXT
} else {
print('Wrong Answer');//INTO TEXT
}
}
})
],
),
),
);
}
}

Below the RaisedButton add a Text Widget. It should look something like this:
Text(output)
, then replace the print() statement with a setState() function updating the output:
setState(() {output = 'Correct';});
To not get an error in the first place you have to initialize the output variable, so instead of only writing
String output;
write
String output = "";

Related

Flutter with SQFlite error on pushing to database

I convert the data from my class instance to a map then pass that map into a database which I think is set up correctly but am getting the following error:
Tried calling: insert(conflictAlgorithm: Instance of 'ConflictAlgorithm', data: _LinkedHashMap len:5, table: "sessionchunk")
Found: insert(String, Map<String, Object?>, {String? nullColumnHack, ConflictAlgorithm? conflictAlgorithm}) => Future<int>
heres my code:
globals.dart (bad file name, more of a database helper file)
library data_practice.globals;
import 'models/sessionModel.dart';
import "package:sqflite/sqflite.dart";
import "package:path/path.dart";
var database;
Future<Database> initDatabase() async {
return database = openDatabase(
// path to the database
join(await getDatabasesPath(), 'user_data.db'),
// database version
version: 1,
// on create
onCreate: (db, version) {
return db.execute(
"CREATE TABLE sessionchunk(id INTEGER PRIMARY KEY, worktime INTEGER, breaktime INTEGER, intention TEXT, progress TEXT)");
});
}
// create an instance of this to get access to the db
pushChunk(SessionChunk chunk) async {
//create instance of the mysql database, this might cause issues
//by having multiple instances??
var db = await database;
//takes table name,
await db.insert(
table: 'sessionchunk',
data: chunk.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace);
}
sessionModel.dart (this is the main model that I'm trying to store into the sessionchunk table)
import "package:path/path.dart";
import "package:sqflite/sqflite.dart";
import "package:data_practice/main.dart";
import "package:data_practice/globals.dart" as globals;
class SessionChunk {
int id = 0;
int workTime = 40;
int breakTime = 10;
String intention = "finish backend";
String progress = "done";
SessionChunk({required id, worktime, breakTime, intention, progress});
// helper method: converts chunk data into map for sqflite db
Map<String, dynamic> toMap() {
return {
"id": this.id,
"worktime": this.workTime,
"breaktime": this.breakTime,
"intention": this.intention,
"progress": this.progress,
};
}
// helper method: prints current values of refrenced session instance
#override
String toString() {
return 'SessionChunk{id: $id, workTime: $workTime, breakTime: $breakTime, intention: $intention, progress: $progress}';
}
}
then my main.dart file:
import 'package:flutter/material.dart';
import "package:path/path.dart";
import "package:sqflite/sqflite.dart";
import "./models/sessionModel.dart";
import 'globals.dart' as globals;
//TODO: left off at step 5 in on https://docs.flutter.dev/cookbook/persistence/sqlite
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Database db = await globals.initDatabase();
print(db);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Push to database, press below',
),
TextButton(
onPressed: () {
var chunk = SessionChunk(
id: 1,
);
globals.pushChunk(chunk);
},
child: Text("push"),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Any help with how doing this would be greatly appreciated, pretty new to all this so please explain like Im 5! Happy Friday :)

API data display - flutter card widget

Get API connection is successful. but I have no idea how to map data.. how is connect snapshot.data,
I want to display data in a Stack widget.
https://flutter.dev/docs/cookbook/networking/fetch-data
I learned this from the association with this source
Future<News> fetchNews() async {
final response =
await http.get('#url');
print(response.body);
if (response.statusCode == 200) {
return News.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load news');
}
}
class News {
final String title;
final String description;
final String image;
News({this.title, this.description, this.image});
factory News.fromJson(Map<String, dynamic> json) {
return News(
title: json['title'],
description: json['description'],
image: json['image'],
);
}
}
Widget _buildPage(BuildContext context, int direction) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: FutureBuilder<News>(
future: futureNews,
builder: (context, snapshot) {
if (snapshot.hasData) {
return newsCard(snapshot.data);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
);
}
Widget newsCard(size){
return Stack(
children: <Widget>[
Container(
child: Image.network(
image,
fit: BoxFit.cover
),
height: size.height/2.0,
),
),
],
);
}
Your code is a bit messy and it doesn't make much sense. It seems obvious that the data is not getting displayed because you're passing your News object to your newsCard function, but the parameter seems to be expecting Size. I also don't know where are you getting the image property from since it doesn't seem to be declared anywhere in the code.
Doing some changes to your code, a minimal working function that returns your widget would look like this:
Widget _buildPage(BuildContext context, int direction) {
Size size = MediaQuery.of(context).size;
return SafeArea(
child: FutureBuilder<News>(
future: futureNews,
builder: (context, snapshot) {
if (snapshot.hasData) {
return newsCard(snapshot.data, size);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
);
}
Widget newsCard(News news, Size size){
return Stack(
children: <Widget>[
Container(
child: Image.network(
news.image,
fit: BoxFit.cover
),
height: size.height/2.0,
),
),
],
);
}
UPDATE
If you're getting the error you mentioned bellow, is likely that your response from the get request is a list of News and not just one News object, therefore you'll have to change this:
return News.fromJson(jsonDecode(response.body));
To this:
return jsonDecode(response.body).map<News>((object) => News.fromJson(object)).toList();
The return type of fetchNews() should be Future<List<News>> instead of Future<News>

TextField on change, call api - how to throttle this?

If I have a textfield, and on change in that textfield, I call a function, which calls an API, how can I throttle that, so it calls that function only if user has not typed anything for 1 second?
Im lost here.. any help is more than welcome.
Use a Timer.
If a key is pressed before one second cancel the old timer and reschedule with a new Timer, otherwise make the API call:
import 'dart:async';
class _MyHomePageState extends State<MyHomePage> {
String textValue;
Timer timeHandle;
void textChanged(String val) {
textValue = val;
if (timeHandle != null) {
timeHandle.cancel();
}
timeHandle = Timer(Duration(seconds: 1), () {
print("Calling now the API: $textValue");
});
}
#override
void dispose() {
super.dispose();
timeHandle.cancel();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.all(20),
alignment: Alignment.center,
child: TextField(
onChanged: textChanged,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Please enter a search term')),
),
],
),
),
);
}
}
You need to make use of a class named CancelableOperation from the async package.
You can declare it in your stateful widget, outside the build() method:
CancelableOperation cancelableOperation;
And use it like so within your onChanged callback:
cancelableOperation?.cancel();
cancelableOperation = CancelableOperation.fromFuture(Future.delayed(Duration(seconds: 1), () {
// API call here
}));

Trying to make radio buttons with using Streambuilder and Bloc in Flutter. but don't work

I tried to make radiobuttons by using Streambuilder and Bloc.
so I made streamcontroler and when radiobuttons clicked,
I made streamcontrl.add(value) implemented, but Streambuilder don't listen
that stream. I tested onchanged value of radio. and
Please figure out what's wrong with it.
This is full code.
import 'package:flutter/material.dart';
import 'dart:async';
void main(){
runApp(new MaterialApp(
home: new MyApp(),
));
}
class bloc {
StreamController <int> ctrl = StreamController() ;
get blocvalue => ctrl.stream;
void setvalue (value ) {
ctrl.sink.add(value) ; }
}
class MyApp extends StatefulWidget {
#override
_State createState() => new _State();
}
class _State extends State<MyApp>{
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Name here'),
),
body: new Container(
padding: new EdgeInsets.all(15.0),
child: new Center(
child: new Column(
children: <Widget>[
StreamBuilder(
stream: bloc().blocvalue,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot <int> snapshot)
{
List<Widget> list = new List<Widget>();
for(int i = 0; i < 3; i++){
list.add(new RadioListTile(
value: i,
groupValue: snapshot.data,
onChanged: bloc().setvalue,
activeColor: Colors.green,
controlAffinity: ListTileControlAffinity.trailing,
title: new Text('Item: ${i}'),
dense: true,
// subtitle: new Text('sub title'),
));
}
return Column(children: list,); })
],
),
),
),
);
}
}
As mentioned by pksink in the comments, you're creating a new bloc inside build by calling setting it in StreamBuilder as bloc().blocValue. What you can do here is declare it as final myBloc = bloc(); outside of the bloc and set it on your StreamBuilder as myBloc.blocValue. With this, a new instance of bloc won't be created with every rebuild of Widget build.

Strange red Block under Flutter TextField Widget

I'm working on a shopping list in one tab of my flutter app but under the Input field i always get and strange red block when the keyboard comes up (red block stays there until keyboard goes away)
RedBlock which appears with keyboard
Debug report which shows up after clicking into the field
Performing full restart...
Restarted app in 1.172ms.
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStageprocessPointer 0
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStageprocessPointer 1
I/flutter (28869): [{name: Lukas, id: 1, value: 32}, {name: Sophie, id: 2, value: 20}, {name: Peter, id: 3, value: 45}]
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStage processPointer 0
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStage processPointer 1
V/InputMethodManager(28869): Starting input: tba=android.view.inputmethod.EditorInfo#b63ece2 nm : com.yourcompany.flutterapp ic=io.flutter.plugin.editing.InputConnectionAdaptor#484e873
I/InputMethodManager(28869): [IMM] startInputInner - mService.startInputOrWindowGainedFocus
D/InputTransport(28869): Input channel constructed: fd=101
D/InputTransport(28869): Input channel destroyed: fd=100
D/InputMethodManager(28869): ISS - flag : 0Pid : 28869 view : com.yourcompany.flutterapp
D/ViewRootImpl#da3a8cd[MainActivity](28869): MSG_RESIZED: frame=Rect(0, 0 - 1080, 2220) ci=Rect(0, 63 - 0, 918) vi=Rect(0, 63 - 0, 918) or=1
D/ViewRootImpl#da3a8cd[MainActivity](28869): Relayout returned: oldFrame=[0,0][1080,2220] newFrame=[0,0][1080,2220] result=0x1 surface={isValid=true -887126016} surfaceGenerationChanged=false
Here you can see my code i have written:
import 'dart:async';
import 'dart:core';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class ShoppingBasket extends StatefulWidget {
#override
ShoppingBasketState createState() => new ShoppingBasketState();
}
class ShoppingBasketState extends State<ShoppingBasket> {
Directory documentsDirectory;
String dirPath;
Database database;
List<Map> listRecords;
Widget listView;
final TextEditingController _controller1 = new TextEditingController(); // name field
final TextEditingController _controller2 = new TextEditingController(); // value field
#override
void initState() {
listView = beforeDataFetchIsFinished();
getPathAndCheckForDbAndPrepareListView();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Column(
children: <Widget>[
inputFieldCard(),
listView, //--> List view gets after all data was fetched here
],
),
);
}
//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
//View Build ------------------------------------------------------------------------
/// Set the listview variable with an CircularPorgressIndicator.
/// gets overriden if the real listview has finished.
Widget beforeDataFetchIsFinished() {
return new Container(
margin: new EdgeInsets.fromLTRB(0.0, 30.0, 0.0, 0.0),
child: new Center(
child: new CircularProgressIndicator(
strokeWidth: 2.0,
),
),
);
}
/// The Inputfield card in one methode.
/// Returns the InputCard as one widget.
Widget inputFieldCard() {
return new Container(
child: new Card(
child: new Container(
child: new Column(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Container(
width: 150.0,
padding: new EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 10.0),
child: new TextField(
controller: _controller1,
decoration: new InputDecoration(
hintText: 'Name...',
),
),
),
new Container(
width: 150.0,
padding: new EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 10.0),
child: new TextField(
keyboardType: TextInputType.number,
controller: _controller2,
decoration: new InputDecoration(
hintText: 'Value...',
),
),
),
],
),
new Container(
padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 20.0),
child: new RaisedButton(
color: Colors.green,
child: new Text('Insert Data', style: new TextStyle(color: Colors.white),),
onPressed: () {
insertToDb(_controller1.text, _controller2.text);
_controller1.clear();
_controller2.clear();
},
),
),
],
)
),
), //top card end
);
}
/// the CircularProgressIndicator gets overiden if this
/// methode gets all its data --> then rerender.
Widget injectListViewAfterAllDataIsFetched() {
return new Card(
child: new Container(
child: new ListView.builder(
shrinkWrap: true, //<-- Necessary because Listveiw inside Column
itemCount: listRecords == null ? 0 : listRecords.length,
itemBuilder: (BuildContext context, int index) {
return new ListTile(
title: new Text(listRecords[index]['name']),
);
},
),
),
);
}
//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
//Data-Base Operations --------------------------------------------------------------
/// Start up --> Open db and fetching data when complete
/// start render engine again.
Future<bool> getPathAndCheckForDbAndPrepareListView() async {
documentsDirectory = await getApplicationDocumentsDirectory();
String dirPath = documentsDirectory.path;
List content = documentsDirectory.listSync();
final File file = new File(dirPath + '/myDataBase.db');
if(!content.contains(file)) { //Check if db exists
await createDbIfNotExists(file); //if not create it
}
print(await getRecords());
listRecords = await getRecords();
print(listRecords);
setState(() {
listView = injectListViewAfterAllDataIsFetched();
});
return true;
}
/// Inserting data into the data base.
/// #return true.
Future<bool> insertToDb(String name, String value) async {
if(name != '' && value != '') {
var valueSql = int.parse(value);
String sql = 'INSERT INTO Test(name, value) VALUES("$name", $valueSql)';
await database.inTransaction(() async {
await database.rawInsert(sql);
});
listRecords = await getRecords();
setState(() {
listView = injectListViewAfterAllDataIsFetched();
});
return true;
} else {
return false;
}
}
/// Gives the whole Db back.
/// #return Map with all records.
Future<List<Map>> getRecords() async {
return await database.rawQuery('SELECT * FROM Test');
}
/// Creating the given File (should be an .db file).
/// #param file Gives the file (.db) which gets created.
/// #return true.
Future<bool> createDbIfNotExists(File file) async {
database = await openDatabase(file.path, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
"CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER)");
});
return true;
}
}
Does someone of you understand why this is showing up? And have an smart Solution to fix it?
Edit: Some Photos which show my Keyboard with shortcuts and without them
I was facing the same problem. Just set resizeToAvoidBottomPadding false in you scaffold and it should solve the problem.
The red bar indicates that the content of one of your containers or columns are bigger, than allowed by their parent. I cant reproduce this issue on iOS or Android. Also, why is the raised button not displayed in your screenshot?