Make a specific action exlusive to only one Button - oop

I'm new to flutter and OOP in general, I'm making an app that tells you to chose an article for a German word.
I want to know how to change the color of the pressed button only depending on if the answer is correct or no and disabling all the buttons in the same time. but when pressed all the 3 buttons change color and are disabled.
here is my button class
import 'package:flutter/material.dart';
class ArticleButton extends StatelessWidget {
#override
final String article;
final Function check;
final bool onPushed;
final Color bgColor;
ArticleButton({this.article,this.check,this.onPushed,this.bgColor});
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: FlatButton(
onPressed: onPushed? check:null,
child: Text(
"$article",
style: TextStyle(
fontSize: 20.0,
fontFamily: 'Roboto',
),),
splashColor: Colors.grey,
disabledColor: bgColor,
),
);
}
}
here is my main function
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'services/word.dart';
import 'package:germanarticle/button.dart';
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Word> words =[
Word(article: "Der",word: "Apfel"),
Word(article: "Die",word: "Erdbeere"),
Word(article: "Das",word: "Auto"),
];
List<String> articles=['Der',"Die","Das"];
int index =0;
int score =0;
bool enabled=true;
Color bgColor=Colors.blue;
#override
Widget build(BuildContext context) {
return Scaffold(
body:Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("$score"),
Text("${words[index].word}"
,style: TextStyle(
fontSize: 60.0,
),
),
SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:
articles.map((e)=>ArticleButton(
article:e,
check:(){
if (words[index].article == e){
setState(() {
score++;
bgColor=Colors.green;
}
);
}else{
setState(() {
enabled=false;
bgColor=Colors.red;
});
}
},onPushed: enabled,
bgColor: bgColor,
)
).toList(),
),
FlatButton(
onPressed: () {
setState(() {
index++;
enabled =true;
});
},
child: Text("next"),
)
],
),
);
}
}
thank you

Try this, it works perfectly:
// an enum for all your button state
enum ButtonStatus {correct, wrong }
// get the color of your button based on the button state
Color getButtonStatus(ButtonStatus buttonStatus) {
switch (buttonStatus) {
case ButtonStatus.correct:
return Colors.green;
break;
case ButtonStatus.wrong:
return Colors.red;
break;
default:
return Colors.blue;
break;
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Word> words = [
Word(article: "Der", word: "Apfel"),
Word(article: "Die", word: "Erdbeere"),
Word(article: "Das", word: "Auto"),
];
// define a button status object here
ButtonStatus buttonStatus;
List<String> articles = ['Der', "Die", "Das"];
int index = 0;
int score = 0;
Color bgColor = Colors.blue;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("$score"),
Text(
"${words[index].word}",
style: TextStyle(
fontSize: 60.0,
),
),
SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: articles
.map((e) => ArticleButton(
article: e,
check: () {
if (words[index].article == e) {
setState(() {
score++;
// change the color of the button if correct
buttonStatus = ButtonStatus.correct;
});
} else {
setState(() {
// change the color of the button if wrong
buttonStatus = ButtonStatus.wrong;
});
}
},
onPushed: enabled,
bgColor: bgColor,
))
.toList(),
),
FlatButton(
// add the color to your flat button, it changes if the answer is correct or wrong and if the button is disabled
color: getButtonStatus(buttonStatus),
onPressed: () {
setState(() {
index++;
});
},
child: Text("next"),
)
],
),
);
}
}
I hope this helps.

Thats because you aren't changing your index variable inside map function, so it is 0 all the way. Provide some screenshots / sketches about what are you trying to achieve with the app.

Related

A resource failed to call close -flutter/tflite error

I want to do image processing in flutter. I load the ml model(tflite) in flutter. Here I successfully take the image from gallery/camera . I stuck in processing part of the image .I didnt get the required ouput. please help me
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:tflite/tflite.dart';
void main() {
runApp(new MaterialApp(
title: "corona",
home: LandingScreen(),
));
}
class LandingScreen extends StatefulWidget {
#override
_LandingScreenState createState() => _LandingScreenState();
}
class _LandingScreenState extends State<LandingScreen> {
File imageFile;
String result;
String path;
_openGallery(BuildContext context) async {
var picture = await ImagePicker.pickImage(source: ImageSource.gallery);
this.setState(() {
imageFile = picture;
path = picture.path;
});
Navigator.of(context).pop();
}
_openCamera(BuildContext context) async {
var picture = await ImagePicker.pickImage(source: ImageSource.camera);
this.setState(() {
imageFile = picture;
path = picture.path;
});
Navigator.of(context).pop();
}
// **classifyimage function to process the image from tflite**
Future classifyImage() async {
await Tflite.loadModel(
model: "assets/covid19_densenet.tflite",
labels: "assets/x.txt",
);
var output = await Tflite.runModelOnImage(path: path);
setState(() {
result = output.toString();
});
}
// Other functions
Future<void> _showChoiceDialog(BuildContext context) {
return showDialog(context: context, builder: (BuildContext context) {
return AlertDialog(
title: Text("Make a Choose!"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
GestureDetector(
child: Text("Gallery"),
onTap: () {
_openGallery(context);
},
),
Padding(padding: EdgeInsets.all(8.0)),
GestureDetector(
child: Text("Camera"),
onTap: () {
_openCamera(context);
},
)
],
),
),
);
});
}
Widget _decideImageView() {
if (imageFile == null) {
return Text("No Image Selected!");
} else {
return Image.file(imageFile, width: 400, height: 400);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("CORONA DETECTION"),
),
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
_decideImageView(),
RaisedButton(
onPressed: () {
_showChoiceDialog(context);
},
child: Text("select image!"),
),
Container(
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: RaisedButton(
onPressed: () => classifyImage(),
child: Text('Classify Image'),
textColor: Colors.white,
color: Colors.blue,
padding: EdgeInsets.fromLTRB(12, 12, 12, 12),
),
),
result == null ? Text('Result') : Text(result)
],
),
),
),
);
}
}
This is an UI of application. when i tap on the classify image button
Here i am trying to upload image to model by this button and then it processing and returns the output
The tflite seems to be throwing a BufferOverflowException due to lack of grayscale support on onFrame methods. The issue should have been fixed as mentioned on this GitHub issue ticket.

How to wait for variable to not equal to null in a future builder (Flutter/Dart)?

I have a simple app with two dart files: main.dart and bukalapak.dart
For demonstration purposes the app only has two Future Text() widgets. Basically one Text widget gets the name of a certain html, the other widget gets the total of the same html. Don't ask why but the future builder for "name" has to be in a separate stateful widget in bukalapak.dart. My question is how can I wait until the html is not null then display the total Text widget, because I can easily just call the url again but that would be doing twice the work. I only want to have to call the http.get once.
Here is the code for main.dart:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
Bukalapak bukalapak = Bukalapak();
return Scaffold(
appBar: AppBar(
title: Text('data'),
),
body: Container(
child: Column(
children: <Widget>[
RandomWidget(
bukalapak: bukalapak,
),
FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Total results: ${snapshot.data}')),
);
},
future: bukalapak.getTotal(),
)
],
),
),
);
}
}
The code for bukalapak.dart:
class Bukalapak {
var html;
Future<dynamic> getTotal() async {
// wait until html != null, then perform this
var a = html.querySelectorAll(
'#display_product_search > div.product-pagination-wrapper > div.pagination > span.last-page');
dynamic total = int.parse(a[0].text) * 50;
total = '$total'.replaceAllMapped(
new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
return total;
}
Future<dynamic> getName() async {
http.Response response = await http.get(
'https://www.bukalapak.com/products/s?from=omnisearch&from_keyword_history=false&page=0&search%5Bkeywords%5D=paper&search_source=omnisearch_organic&source=navbar&utf8=✓');
if (response.statusCode == 200) {
String data = response.body;
html = parse(data);
var nameElement = html.querySelector(
'li.col-12--2 > div.product-card > article > div.product-media > a');
String title = nameElement.attributes['title'];
return title;
} else {
throw Exception('Bukalapak error: statusCode= ${response.statusCode}');
}
}
}
class RandomWidget extends StatefulWidget {
RandomWidget({this.bukalapak});
final Bukalapak bukalapak;
#override
_TextState createState() => _TextState();
}
class _TextState extends State<RandomWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Name results: ${snapshot.data}')),
);
},
future: widget.bukalapak.getName(),
);
}
}
you can pass any function which notify parent widget to build future.
Following code will help you more:
class DeleteWidget extends StatefulWidget {
#override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
Bukalapak bukalapak = Bukalapak();
Widget first;
bool isBuild = false;
nowbuildtotal() async {
await Future.delayed(Duration(microseconds: 1));
setState(() {
isBuild = true;
});
}
#override
void initState() {
super.initState();
first = RandomWidget(
bukalapak: bukalapak,
buildnow: nowbuildtotal,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('data'),
),
body: Container(
child: Column(
children: <Widget>[
first,
isBuild
? FutureBuilder(
builder: (context, snapshot) {
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Total results: ${snapshot.data}')),
);
},
future: bukalapak.getTotal(),
)
: Container()
],
),
),
);
}
}
class RandomWidget extends StatefulWidget {
RandomWidget({this.bukalapak, this.buildnow});
final Bukalapak bukalapak;
final Function buildnow;
#override
_TextState createState() => _TextState();
}
class _TextState extends State<RandomWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
widget.buildnow();
}
return Container(
color: Colors.grey,
height: 28.0,
padding: EdgeInsets.only(left: 20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text('Name results: ${snapshot.data}')),
);
},
future: widget.bukalapak.getName(),
);
}
}
class Bukalapak {
var html;
Future<dynamic> getTotal() async {
// wait until html != null, then perform this
var a = await html.querySelectorAll(
'#display_product_search > div.product-pagination-wrapper > div.pagination > span.last-page');
dynamic total = int.parse(a[0].text) * 50;
total = '$total'.replaceAllMapped(
new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
return total;
}
Future<dynamic> getName() async {
print("object");
http.Response response = await http.get(
'https://www.bukalapak.com/products/s?from=omnisearch&from_keyword_history=false&page=0&search%5Bkeywords%5D=paper&search_source=omnisearch_organic&source=navbar&utf8=✓');
if (response.statusCode == 200) {
String data = response.body;
html = parse(data);
var nameElement = html.querySelector(
'li.col-12--2 > div.product-card > article > div.product-media > a');
String title = nameElement.attributes['title'];
return title;
} else {
throw Exception('Bukalapak error: statusCode= ${response.statusCode}');
}
}
}

how to show video with video player in flutter

how to show video in flutter?
i should recieve an api have url of video to show, but it sitll white page with my progress indicator,
I was trying for a week but couldn't do any thing,
then I tried to use assets video but it didn't work too
here is my code so what is wrong?
please help me, thank you.
class _MyHomePageState extends State<MyHomePage> {
VideoPlayerController _videoPlayerController;
Future<void> _initializedVideoPlayerFuture;
String videoUrl =
'https://storage.koolshy.co/shasha-transcoded-videos-2019/1c18ada9-a82a-4490-ad2f-87c3ba3ed251_240.mp4';
String videoTrack = 'assets/video.mp4';
#override
void initState() {
super.initState();
// _videoPlayerController = VideoPlayerController.network(videoUrl);
_videoPlayerController = VideoPlayerController.asset(videoTrack);
_videoPlayerController.setLooping(true);
_videoPlayerController.setVolume(1.0);
}
#override
void dispose() {
super.dispose();
_videoPlayerController.dispose();
}
void _incrementCounter() {
setState(() {
_videoPlayerController.value.isPlaying
? _videoPlayerController.pause()
: _videoPlayerController.play();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FutureBuilder(
future: _initializedVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'play/pause',
child: Icon(_videoPlayerController.value.isPlaying
? Icons.pause
: Icons.play_arrow),
),
);
}
}
there is a missing statement
_initializedVideoPlayerFuture = _videoPlayerController.initialize();
should be in the initstate()
void initState() {
super.initState();
_videoPlayerController = VideoPlayerController.network(videoUrl);
// _videoPlayerController = VideoPlayerController.asset(videoTrack);
_initializedVideoPlayerFuture = _videoPlayerController.initialize();
_videoPlayerController.setLooping(true);
_videoPlayerController.setVolume(1.0);
}

Can I get the same effect in flutter as the <TouchableOpacity /> in React Native?

I found that in React Native, when using component, pressing the corresponding area can have a opacity effect.
In flutter, we sure can use InkWell widget, but i don't want a rectangle or square. Can we implement the same result using flutter. Cheers!
Use the code below:
import 'package:flutter/material.dart';
class TouchableOpacity extends StatefulWidget {
final Widget child;
final Function onTap;
final Duration duration = const Duration(milliseconds: 50);
final double opacity = 0.5;
TouchableOpacity({#required this.child, this.onTap});
#override
_TouchableOpacityState createState() => _TouchableOpacityState();
}
class _TouchableOpacityState extends State<TouchableOpacity> {
bool isDown;
#override
void initState() {
super.initState();
setState(() => isDown = false);
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (_) => setState(() => isDown = true),
onTapUp: (_) => setState(() => isDown = false),
onTapCancel: () => setState(() => isDown = false),
onTap: widget.onTap,
child: AnimatedOpacity(
child: widget.child,
duration: widget.duration,
opacity: isDown ? widget.opacity : 1,
),
);
}
}
Usage:
TouchableOpacity(
child: ....
onTap: () {....}
)
#Shan Liu you are correct that InkWell has its own "splash" effect which makes the rectangle or square you mentioned.
If you don't want that splash effect, use GestureDetector.
In below example, I put a Text inside a GestureDetector, but you can put your widget there instead:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = 'InkWell Demo';
return MaterialApp(
title: title,
home: MyHomePage(title: title),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(child: MyButton()),
);
}
}
class MyButton extends StatefulWidget {
#override
MyButtonState createState() {
return MyButtonState();
}
}
class MyButtonState extends State<MyButton> {
bool isTappedDown = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
},
onTapDown: (tapDownDetails) {
setState(() {
isTappedDown = true;
});
},
onTapUp: (tapUpDetails) {
setState(() {
isTappedDown = false;
});
},
child: Text(
'Flat Button',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: isTappedDown ? Colors.black.withOpacity(0.5) : Colors.black),
),
);
}
}
I think you'll need to combine a gesture detector and an opacity animation. I couldn't find a ready to use example. But here is the example for opacity animation.
Flutter opacity animation
Here's a touchable class I created. (You could easily add transparency here)
class Touchable extends StatelessWidget {
final Widget child;
final Function() onPress;
final double borderRadius;
final double padding;
const Touchable(
{Key key, this.child, this.onPress, this.borderRadius, this.padding})
: super(key: key);
#override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(borderRadius),
child: Material(
color: Colors.transparent,
child: InkWell(
child: Padding(
padding: EdgeInsets.all(padding),
child: child,
),
onTap: this.onPress),
),
);
}
}

how to save and load shared preference towards an other page in flutter

I tried to Save and share a variable Phone number string from a tabbar page to homepage. Currently my variable is display only after reload. I tried to display variable just after saved it.
my code :
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _variable;
#override
void initState() {
super.initState();
_loadvariable();
}
_loadvariable() async { // load variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_variable = (prefs.getString('variable'));
}
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
bottomNavigationBar: BottomAppBar(
color: Colors.blue,
elevation: 20.0,
child: ButtonBar(
alignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(Icons.phone),
color: Colors.white,
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new Phone_Page()),
);
},
),
],
),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'$_variable',
style: Theme.of(context).textTheme.display1,
),
],
),
),
);
}
}
here is my seconde page class, I can clic on the phone icon to show a dialog box, and I can write on the text field. After clic on save button my textfield is save, the dialog box is close and my variable is display on the card. But after return on the Homepage my variable isn't display. I need to reload the app to display it :(
class Phone_Page extends StatefulWidget {
#override
Phone_PageState createState() => Phone_PageState();
}
class Phone_PageState extends State<Phone_Page> {
final TextEditingController controller = new TextEditingController();
String _variable;
_loadvariable() async { // load variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_variable = (prefs.getString('variable'))?? "";
});
}
_savevariable() async { // save variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.setString('variable', controller.text);
});
}
_deletevariable() async { //delete variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.remove('variable');
});
}
#override
void initState() {
super.initState();
_loadvariable()?? "";
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Phone"),
),
body: new Center(
child: new ListView(
children: <Widget>[
new Card(
child: new Container(
padding: const EdgeInsets.all(20.0),
child: new Row(
children: [
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Text(
'$_variable',
style: new TextStyle(
color: Colors.grey[500],
),
),
],
),
),
new IconButton(
icon: new Icon(Icons.add_call),
onPressed: ()
{
_showDialog();
}
),
new IconButton(
icon: new Icon(Icons.delete),
onPressed: () { setState(() {
_deletevariable();
_savevariable();
_loadvariable();
}
);
},
),
],
),
),
),
]
)
)
);
}
_showDialog() async {
await showDialog<String>(
context: context,
child: new AlertDialog(
// contentPadding: const EdgeInsets.all(16.0),
content: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
controller: controller,
autofocus: true,
decoration: new InputDecoration(
labelText: 'number', hintText: '06 - - - - - - - -'),
// keyboardType: TextInputType.number,
),
)
],
),
actions: <Widget>[
new FlatButton(
child: const Text('save'),
onPressed: (){
setState(() { {
_savevariable();
Navigator.pop(context);
}
}
);
}
)
],
),
);
}
}
To achieve what you want, you need to call _loadvariable() function of class MyHomePage from PhonePage class. To do that:
Refactor and remove _ from _loadvariable() and _MyHomePageState so that it won't be private anymore.
Pass MyHomePageState class instance to PhonePage as follows:
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new PhonePage(
myHomePageState: this,
)),
);
Call loadvariable() in _savevariable() like
_savevariable() async {
// save variable
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.setString('variable', controller.text);
});
widget.myHomePageState.loadvariable();
}
Make sure the myHomePageState type is var so that you won't get type error:
class PhonePage extends StatefulWidget {
var myHomePageState;
PhonePage({this.myHomePageState});
#override
PhonPageState createState() => PhonPageState();
}