sms_autofill Unable to detect the OTP - flutter

I have used the sms_autofill plugin to to auto-detect the OTP received on mobile and type it in the given PinFieldAutoFill, As per https://pub.dev/packages/sms_autofill#-readme-tab- I am using await SmsAutoFill().listenForCode; function before making my API request & when the request has got a 200 status code I'm navigating it to another page and in init I'm listening to the OTP SMS received by using await SmsAutoFill().listenForCode; I thought like maybe when the page is initialized it wont be listening again to any SMS so i did add a Timer also but still it was not receiving anything.
Dependency - sms_autofill: ^1.2.6
Code : Page1
Center(
child: RaisedButton(
child: Text('Register'),
onPressed: () async {
await SmsAutoFill().listenForCode;
final signCode = await SmsAutoFill().getAppSignature;
print(signCode);
//Http request code
},
),
),
Code : Page2
String appSignature;
String otpCode;
Timer timer;
#override
void codeUpdated() {
setState(() {
otpCode = code;
});
}
#override
void initState() {
super.initState();
listenOTP();
// timer = Timer.periodic(Duration(seconds: 10), (Timer t){
// print('OTP Listening');
// listenOTP();
// });
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Code Received: $otpCode",
),
Container(
padding: EdgeInsets.symmetric(horizontal: 50),
child: PinFieldAutoFill(
codeLength: 6,
onCodeChanged: (val) {
print(val);
},
),
)
],
),
),
);
}
void listenOTP() async {
print('listen for code');
await SmsAutoFill().listenForCode;
}

Maybe your sms format is not right. The sms format should be like:
ExampleApp: Your code is 123456
FA+9qCX9VSu //this is your app signature
if your message is different. You can follow this answer to handle any type of sms format otp https://stackoverflow.com/a/70076071/6067774

Related

How to place a Loader on the screen while an API action is being performed in Flutter

I am trying to show a loader when a form is submitted to the server so that there isn't another submission of the same form until and unless the API sends back a response. I have tried something like the below code but it just doesn't seem to work as the Circular Progress indicator seems to not show up and rather, the screen remains as it is until the server sends back a response. As a result of this, the user gets confused as to whether or not their requests got submitted, and in the process, they end up posting the same form another time only to find out later that their were multiple submissions. I will include snippets of the code that has the CircularProgressIndicator() to prevent another submission and the widget that has the API call code.
bool isSelected = false;
isSelected
? const CircularProgressIndicator() : Container(
child: Center(
child: AppButtonStyle(
label: 'Submit',
onPressed: () {
if (_key.currentState!.validate()) { //This is the key of the Form that gets submitted
setState(() {
isSelected = true;
});
List<String> date = [
dateFormat.format(_dateTimeStart!).toString(),
dateFormat.format(_dateTimeEnd!).toString()
];
Map<String, dynamic> data = {
'leave_type': _selectedItem,
'dates': date,
'description': add
};
if (kDebugMode) {
print('DATA: $data');
}
Provider.of<LeaveViewModel>(context, listen: false)
.postLeaveRequests(data, context) //This here makes the API call
.then((value) {
setState(() {
isSelected = false;
_textController.clear();
_dateTimeStart = null;
_dateTimeEnd = null;
});
});
}
},
),
),
)
The API module:
class LeaveViewModel with ChangeNotifier {
final leaveRepository = LeaveRequestRepository();
Future<void> postLeaveRequests(dynamic data, BuildContext context) async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
String authToken = localStorage.getString('token').toString();
leaveRepository.requestLeave(authToken, data).then((value) {
print('LEAVEEEEEE: $value');
Flushbar(
duration: const Duration(seconds: 4),
flushbarPosition: FlushbarPosition.BOTTOM,
borderRadius: BorderRadius.circular(10),
icon: const Icon(Icons.error, color: Colors.white),
// margin: const EdgeInsets.fromLTRB(100, 10, 100, 0),
title: 'Leave Request Submitted',
message: value.data.toString()
).show(context);
}).onError((error, stackTrace) {
Flushbar(
duration: const Duration(seconds: 4),
flushbarPosition: FlushbarPosition.BOTTOM,
borderRadius: BorderRadius.circular(10),
icon: const Icon(Icons.error, color: Colors.white),
// margin: const EdgeInsets.fromLTRB(100, 10, 100, 0),
title: 'Leave Request Failed',
message: error.toString()
).show(context);
});
}
}
Any help will be appreciated. Also, I'm open to the concept of using easy_loader 2.0.0 instead of CicularProgressIndicator() and would be very glad to read suggestions about it's usage in my code.
One problem in your code seems to be that you define isSelected in your build method. Every time you call setState, the build method is called to regenerate the widgets. And with each new call isSelected gets false as initial value. Define isSelected as class variable, so that it is not always on false.
The more elegant solution would be to work with a FutureBuilder
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

How to take screenshot of entire screen outside of your FLUTTER DESKTOP app(mostly for Windows OS)?

I'm new to flutter. Now I am able to take screenshot for my entire desktop app screen using Screenshot package & storing that image to local storage.
But my requirement is to capture the screenshot of entire screen of the window, like if 2 applications are opened(1 Flutter + 1 any other app e.g. browser) in 1 screen, then we can able to take whole screen's screenshot not only flutter app.
Please help me on how to take entire window's screenshot in Windows OS desktop app?
If it's not possible directly from Flutter, then how to achieve this by implementing some native code with Flutter?
check this completely working as expected
bool _isAccessAllowed = false;
CapturedData? _lastCapturedData;
#override
void initState() {
super.initState();
_init();
}
void _init() async {
_isAccessAllowed = await ScreenCapturer.instance.isAccessAllowed();
}
void _handleClickCapture(CaptureMode mode) async {
Directory directory = await getApplicationDocumentsDirectory();
String imageName =
'Screenshot-${DateTime.now().millisecondsSinceEpoch}.png';
String imagePath =
'${directory.path}/screen_capturer_example/Screenshots/$imageName';
_lastCapturedData = await ScreenCapturer.instance.capture(
mode: mode,
imagePath: imagePath,
silent: true,
);
if (_lastCapturedData != null) {
// ignore: avoid_print
// print(_lastCapturedData!.toJson());
} else {
// ignore: avoid_print
print('User canceled capture');
}
setState(() {});
}
Widget _buildBody(BuildContext context) {
return PreferenceList(
children: <Widget>[
if (Platform.isMacOS)
PreferenceListSection(
children: [
PreferenceListItem(
title: const Text('isAccessAllowed'),
accessoryView: Text('$_isAccessAllowed'),
onTap: () async {
bool allowed =
await ScreenCapturer.instance.isAccessAllowed();
BotToast.showText(text: 'allowed: $allowed');
setState(() {
_isAccessAllowed = allowed;
});
},
),
PreferenceListItem(
title: const Text('requestAccess'),
onTap: () async {
await ScreenCapturer.instance.requestAccess();
},
),
],
),
PreferenceListSection(
title: const Text('METHODS'),
children: [
PreferenceListItem(
title: const Text('capture'),
accessoryView: Row(children: [
CupertinoButton(
child: const Text('region'),
onPressed: () {
_handleClickCapture(CaptureMode.region);
},
),
CupertinoButton(
child: const Text('screen'),
onPressed: () {
_handleClickCapture(CaptureMode.screen);
},
),
CupertinoButton(
child: const Text('window'),
onPressed: () {
_handleClickCapture(CaptureMode.window);
},
),
]),
),
],
),
if (_lastCapturedData != null && _lastCapturedData?.imagePath != null)
Container(
margin: const EdgeInsets.only(top: 20),
width: 400,
height: 400,
child: Image.file(
File(_lastCapturedData!.imagePath!),
),
),
],
);
}
// screen shot taken by the App.
You might try using this package: screen_capturer. It works on Windows, Linux and MacOS.
From the docs:
Example of usage:
import 'package:screen_capturer/screen_capturer.dart';
CapturedData? capturedData = await screenCapturer.capture(
mode: CaptureMode.screen, // screen, window
imagePath: '<path>',
);
CaptureMode.screen is to capture the entire screen.
The screenshot package which you mention is only for taking screenshots for widgets of your app not of whole screen.

I want to update the app version in playstore to show a message dialog to user

I am new flutter .I want to update new version app in playstore to show a message dialog to user to update the new version and I used the plugin version_check 0.2.0.
When the user has already updated, but it still displays Message dialog the same. How not to show message dialog after update.Who can help me?
This my Code
This my Code
This my Code
As everything is not clear in the question, you should follow given steps to achieve the same.
Step 1. Go to Remote Config in firebase and add few parameters shown in the image and then publish it.
Step 2. Create a function VersionCheck and _showVersionDialog as follows:
versionCheck(){
//Get Current installed version of app
WidgetsBinding.instance.addPostFrameCallback((_) async {
final PackageInfo info = await PackageInfo.fromPlatform();
double currentVersion = double.parse(info.version.trim().replaceAll(".", ""));
//Get Latest version info from firebase config
final RemoteConfig remoteConfig = await RemoteConfig.instance;
try {
// Using default duration to force fetching from remote server.
await remoteConfig.fetch(expiration: const Duration(seconds: 0));
await remoteConfig.activateFetched();
remoteConfig.getString('force_update_current_version');
double newVersion = double.parse(remoteConfig
.getString('force_update_current_version')
.trim()
.replaceAll(".", ""));
if (newVersion > currentVersion) {
setState(() {
versionCode = remoteConfig.getString('force_update_current_version');
aboutVersion = remoteConfig.getString('update_feature');
});
_showVersionDialog(context);
}
} on FetchThrottledException catch (exception) {
// Fetch throttled.
print(exception);
} catch (exception) {
print('Unable to fetch remote config. Cached or default values will be '
'used');
}
});
}
_showVersionDialog(context) async {
await showDialog<String>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
String title = "Update Available";
String message =
"About Update: \n";
return ButtonBarTheme(
data: ButtonBarThemeData(alignment: MainAxisAlignment.center),
child: new AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title),
Text("v"+versionCode),
],
),
content: Container(
height: 80,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(message,style: TextStyle(fontWeight: FontWeight.bold),),
Text(aboutVersion),
],
),
),
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: new Text(
'Update',
style: TextStyle(color: Colors.white),
),
color: Color(0xFF121A21),
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
onPressed: () {
_launchURL(PLAY_STORE_URL);
},
),
),
],
),
);
},
);
}
Step 3. Call VersionCheck in init function of your main screen as follows.
#override
void initState() {
Future.delayed(const Duration(milliseconds: 5000), () {
if(mounted){
setState(() {
versionCheck();
});
}
});
super.initState();
}
Step 4. Whenever you want the update dialog to appear on screen just increase the version code value in remote config of firebase than your actual version code value.
This will help you to achieve what you want.

My flutter app, generate multiple register in DB when I press button once

I have an app that contains a form. First, you have to authenticate with your ID, a function checks the date of your last register (if you don't register today, you'll pass. If not you can not log into the form screen). Second, you register your symptoms once a day(restriction of the app), press "ENVIAR(send)" and a POST method storages your data in a DB. It's simple.
In theory, I should see one register per person per day. Now the number of devices with my app installed has increased I can see multiple registers per person in some cases. Curiously the problem happens in just some devices. I cannot detect the problem because with my phone I've never had these kinds of problems (HUAWEI P30 LITE).
I try to debug my code, but it all works perfectly. Could you help or advise me on how to solve this problem, please?
PDT: when I press the button "SEND", the function _submit() is executed, which allows POST the data in the DB. Additionally, to verify the systems works right, I use a developer account with credential "000000000". I had to eliminate many lines, but these are the most important.
Have a nice day.
Thanks
I attach the code:
class Tamizaje1Page extends StatefulWidget {
#override
_Tamizaje1PageState createState() => _Tamizaje1PageState();
}
class _Tamizaje1PageState extends State<Tamizaje1Page> {
final usuariosProvider = new UsuariosProvider();
final appProvider = new AppProvider();
final formKey = GlobalKey<FormState>();
final productoProvider = new ProductosProvider();
ProductoModel producto = new ProductoModel();
AppModel app = new AppModel();
#override
Widget build(BuildContext context) {
final bloc = Provider.of(context);
mostrarPosision();
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Center(child: Text('Cuestionario Diario')),
),
body: WillPopScope(
onWillPop: (){Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => LoginPage()), (route) => false);},
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(15.0),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
_crearBoton1(context),
],
),
),
),
),
),
);
}
Widget _crearBoton1( BuildContext context) {
final size = MediaQuery.of(context).size;
return ButtonTheme(
minWidth: size.width*0.2,
height: size.height*0.07,
focusColor: colorApp,
child: RaisedButton(
child: Container(padding: EdgeInsets.symmetric( horizontal: 80.0, vertical: 15.0),child: Text('Enviar', style: TextStyle(color: Colors.white,fontSize: 16.0),)),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25.0),side: BorderSide(color: Colors.transparent,width: 2.0)),
elevation: 0.0,
color: colorApp,
textColor: Colors.white,
onPressed: ( _guardando ) ? null : _submit,
),
);
}
//THIS FUNCTION SENDS THE DATA WHEN PRESS THE BUTTON
_submit() async {
_noVisibleData();
if ( !formKey.currentState.validate() ) return;
formKey.currentState.save();
if(producto.nroDoc!="000000000" && _currentPosition != null && ((producto.meSiento=='1' && app.diagnostico!='-1') || (producto.meSiento=='0'))){
bool permtirenvioToDB= await productoProvider.crearProducto(producto); //envia los datos
if(permtirenvioToDB==true){
_alertaDeEnvio(context, envio1);
await enviarGMAIL();
appProvider.crearApp(app);
Navigator.push(context, MaterialPageRoute(builder: (context) => AlertPage()));
}else{
contarIntetentosEnvioDB++;
if(contarIntetentosEnvioDB<5)_soloMensaje(context,"Se ha producido un error al enviar el formulario. Por favor... ¡Inténtalo nuevamente!","assets/alerta0/a0i1.svg",80.0);
else _soloMensaje(context,"Por favor, ¡Comuníquese con el área de Tecnologías de la Información!","assets/alerta0/a0i3.svg",80.0);
}
}else{
_alertaDeEnvio(context, envio1);
print('Prueba de desarrollador');
Navigator.push(context, MaterialPageRoute(builder: (context) => AlertPage()));
}
}
}
Thanks, i debugged many option and realised the errors occurs because i have 3 future functions wich execute when i press the button (inside the butto widget). I created i new page with an additional #averride before Widget build exclusive to execute future functions, and it works good.
class _MailDBSendState extends State<MailDBSend> {
#override
void initState() {
super.initState();
_dataBase();
_sendMail();
}
.
.
.
.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(

State does not update until button is pressed twice

I am trying to learn and work with APIs, I am using the Tiingo Stock API to get stock info. My current app is:
class _StockAppState extends State<StockApp> {
String out = "Enter Ticker and press Submit";
Map<String,String> headers = {
'Content-Type': 'application/json',
'Authorization' : <API KEY REMOVED>
};
void getPrice(String tick) async {
if(tick == ""){
out = "Enter Ticker and press Submit";
}else{
Response rep = await get('https://api.tiingo.com/tiingo/daily/$tick/prices', headers: headers);
if(rep.statusCode == 200){
List data = json.decode(rep.body);
Map dataS = data[0];
out = "Price: ${dataS['close']}";
}else{
out = "Error";
}
}
}
#override
void initState() {
super.initState();
}
TextEditingController ticker = new TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Stock App'),),
body: Column(
children: <Widget>[
TextField(
controller: ticker,
textAlign: TextAlign.left,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter Ticker',
hintStyle: TextStyle(color: Colors.grey),
),
),
FlatButton(
onPressed: () async {
FocusScope.of(context).unfocus();
setState(() {
getPrice(ticker.text);
});
},
child: Text('Submit')
),
Text(out),
],
),
);
}
}
So, basically, when you enter a ticker and press submit, the app will change the "out" string var to display the stock price. But for the app to update, I am having to press submit twice.
Could anyone help?
P.S.: I have removed my API key for security reasons.
It is because you have async method in your setState method.
The setState method will be called synchronously.
So here problem is when setState is performed and frame get refreshed your data from api has not arrived yet and it showing you the old data. When you again click the button your out variable have new data (from your first click) which will be shown on the screen and API will be called again.
To solve your problem
FlatButton(
onPressed: () async {
FocusScope.of(context).unfocus();
await getPrice(ticker.text);
setState(() {
});
},
child: Text('Submit')
),
So call the setState method after API call is completed.
To know more about async/await watch this video : https://www.youtube.com/watch?v=SmTCmDMi4BY