Force routing without context - flutter

am working on chat app , now am stuck on the idea of , if one of the two users left the page i wanna force the other user also to leave the page and back to home screen , i tried many things , boolean , conditions , will pop , nothing work , how can i implement a function to do this job , am using flutter , much appreciate .
i tried using boolean to set a condition to check if user exist , i tried to use will pop , i saw a couple of articles bout it , i even tried to set timer to force the second user to leave , but nothing happened , the problem is there's no action from the other user that make him leave the page , with or without on press , while the first user did the action and pressed the button to leave .
this is the button in the home page who do logic to match through firebase
child: ElevatedButton(
onPressed: () async {
var res = await FirebaseFirestore.instance
.doc(
'match/$_currentValue1$_currentValue2$_currentThumbValue')
.get();
var value = res.exists;
print('RESULT = $value');
/// If Code Is Not Exist
try {
if (value == false) {
/// Create Code In Match Document
await FirebaseFirestore.instance
.collection('match')
.doc('$_currentValue1$_currentValue2$_currentThumbValue')
.set({
'user1Id': FirebaseAuth.instance.currentUser!.uid,
'user1Name': userInfo['displayName'] ?? 'username',
'user2Id': '',
'user2Name': '',
});
print('Match Created By ${userInfo['displayName']}');
/// Create Code Reference In Real Time
await codeRef.set({
'code': '$_currentValue1$_currentValue2$_currentThumbValue',
'user1Id': FirebaseAuth.instance.currentUser!.uid,
'user1Name': userInfo['displayName'] ?? 'username',
'user2Id': '',
'user2Name': '',
});
/// Timer To Delete Code If No Match Found
var counter = 10;
Timer.periodic(const Duration(seconds: 1),
(timer) async {
setState(() {
isMatchVisible = false;
});
print(timer.tick);
print('Data Value During Countdown : $value');
counter--;
/// Check If User2 Exist Im Match Document
DocumentSnapshot documentSnapshot =
await FirebaseFirestore.instance
.collection('match')
.doc('$_currentValue1$_currentValue2$_currentThumbValue')
.get();
///
if (documentSnapshot.get('user2Id') != '') {
timer.cancel();
var goToPageUser1 = 2;
Timer.periodic(const Duration(seconds: 2),
(timer) async {
goToPageUser1--;
if (goToPageUser1 == 0) {
timer.cancel();
/// Go To Chat Screen
await Get.toNamed(
'/ChatScreen',
arguments:
'$_currentValue1$_currentValue2$_currentThumbValue',
parameters: {
'name1': userInfo['displayName'],
'Id1': user!.uid,
},
preventDuplicates: false,
);
}
});
} else {
if (counter == 0) {
var failCounter = 5;
Timer.periodic(const Duration(seconds: 1),
(timer) {
setState(() {
showFailResult = true;
});
failCounter--;
if (failCounter == 0) {
timer.cancel();
setState(() {
showFailResult = false;
});
}
});
/// Delete Code From Match Collection
DocumentReference docCode = FirebaseFirestore
.instance
.collection('match')
.doc(
'${_currentValue1.toString()}${_currentValue2.toString()}${_currentThumbValue.toString()}');
await docCode
.delete()
.then((value) =>
print('Match Code Deleted'))
.catchError((error) => print(
"Failed To Delete Match Code: $error"));
/// Delete Room From Real Time
await codeRef.remove();
print('Cancel timer');
timer.cancel();
setState(() {
value = false;
isMatchVisible = true;
print(
'Data Value After Countdown : $value');
});
}
}
});
/// If Code Is Exist
} else if (value == true) {
/// Update Match Document For User1 AND User2
await FirebaseFirestore.instance
.collection('match')
.doc(
'${_currentValue1.toString()}${_currentValue2.toString()}${_currentThumbValue.toString()}',
)
.update({
'user2Id':
FirebaseAuth.instance.currentUser!.uid,
'user2Name':
userInfo['displayName'] ?? 'username',
});
/// Update Match Code In Real Time
await codeRef.update({
'user2Id':
FirebaseAuth.instance.currentUser!.uid,
'user2Name':
userInfo['displayName'] ?? 'username',
});
var goToPageUser2 = 2;
Timer.periodic(const Duration(seconds: 2),
(timer) async {
goToPageUser2--;
if (goToPageUser2 == 0) {
timer.cancel();
/// Go To Chat Screen
await Get.toNamed(
'/ChatScreen',
arguments:
'$_currentValue1$_currentValue2$_currentThumbValue',
parameters: {
'name2': userInfo['displayName'],
'Id2': user!.uid,
},
preventDuplicates: false,
);
}
});
}
} on FirebaseAuthException catch (e) {
showSnackBar(context, e.message!);
}
},
child: SizedBox(
width: 100,
height: 50,
child: Center(
child: Text(
'Match'.tr,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
),

Related

How to call button tap functionality outside of button in Flutter

I want to call the onTap functionality outside of my button. As soon as I receive my OTP, I want to call the onTap of my manually created widget. I have a custom widget called as LoginCTA and I want to call it's onTap after I receive my OTP in initSmsListener method which I called in initState.
My code -
String _comingSms = 'Unknown';
Future<void> initSmsListener() async {
String comingSms;
try {
comingSms = await AltSmsAutofill().listenForSms??"";
} on PlatformException {
comingSms = 'Failed to get Sms.';
}
if(!mounted)
return;
setState(() {
_comingSms=comingSms;
print("\n \n \n Coming SMS - $_comingSms");
otpController.text = _comingSms[23] + _comingSms[24] + _comingSms[25] + _comingSms[26]
+ _comingSms[27] + _comingSms[28];
});
//Apply here -
}
#override
void initState() {
initSmsListener();
super.initState();
}
isOTP
? LoginCTA(
//After input otp
onPressed: () async {
print(Provider.of<APIData>(context, listen: false)
.loggedIN);
if (emailEntered &&
otpController.text.length == 6) {
bool res;
try {
res = await widget.signInWithOTP(
contactController.text, otpController.text);
} catch (e) {
res = false;
print(e);
}
if (res) {
Fluttertoast.showToast(
msg: "Verifying OTP...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
textColor: cardColor,
backgroundColor: primaryTextColor,
fontSize: 16.0,
);
Timer(Duration(seconds: 2), () {
print(Provider.of<APIData>(context,
listen: false)
.loggedIN);
if (Provider.of<APIData>(context,
listen: false)
.loggedIN ==
1) {
Navigator.pop(context);
}
});
}
}
},
btnText: otpButtonText,
isDisabled: isDisabled,
)
: LoginCTA(
//After input mobile number
onPressed: () async {
if (emailEntered &&
contactController.text.length == 10) {
widget.sendOTP(contactController.text);
setState(() {
isOTP = true;
isDisabled = true;
});
} else {
print('kuch na kuch glti');
}
},
btnText: buttonText,
isDisabled: isDisabled,
hasIcon: hasIcon,
),
Just extract the functionality out into its own function. Then you can assign the function to onTap and also call it whenever you like.

Alert Dialog running infinitely

Hello I am trying to run following code, I want to run a specific asynchronous code and show alert dialog until it's running. But the code is not being executed after await showAlertDialog(); this line.
void appendAndRunPythonCode() async {
await showAlertDialog();
await runPythonScript(final_code);
_alertDialogUtils.dismissAlertDialog(context);
}
This is how my showAlertDialog() function is implemented:
Future<void> showAlertDialog() async {
if (!_alertDialogUtils.isShowing) {
await _alertDialogUtils.showAlertDialog(context);
}
}
runPythonCode():
Future<void> runPythonScript(String code) async {
if (inputImg == null) {
ToastUtils.showToastMessage(text: ConstUtils.input_image_empty_notice);
return;
}
if (code.isEmpty) {
ToastUtils.showToastMessage(text: ConstUtils.code_empty);
return;
}
List<String> lines = code.split('\n');
String lastLine = lines.elementAt(lines.length - 4);
if (lastLine.split(' ').elementAt(0).compareTo('outputImage') != 0) {
ToastUtils.showToastMessage(text: ConstUtils.cv_error_line2);
return;
}
data.putIfAbsent("code", () => code);
data.putIfAbsent("inputImg", () => inputImg);
_alertDialogUtils.showAlertDialog(context);
final result = await _channel.invokeMethod("runPythonCVScript", data);
// Add Artifical Delay of 3 seconds..
await Future.delayed(
Duration(seconds: 3),
);
_alertDialogUtils.dismissAlertDialog(context);
setState(
() {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
output = result['textOutput'] ??= "";
error = result['error'] ??= "";
outputImg = (result['graphOutput']);
data.clear();
},
);
}
You shouldn't await the showAlertDialog because runPythonScript won't be executed until the dialog is dismissed.
Remove the await.
Like so:
void appendAndRunPythonCode() async {
showAlertDialog();
await runPythonScript(final_code);
_alertDialogUtils.dismissAlertDialog(context);
}

Flutter 'value >= min && value <= max': is not true

I am building a simple music player type app. I am facing an issue when my audio completed the time it's showing
'package:flutter/src/material/slider.dart': Failed assertion: line 166 pos 15: 'value >= min && value <= max': is not true.
My code
Expanded(
child: Slider(
activeColor: Color(0xffe7ad29),
inactiveColor: Color(0xFF707070),
value: model.playerBarValue,
onChanged: (val) {
model.seekFromBar(val);
},
),
),
class PlayerProvider extends ChangeNotifier {
final player = AssetsAudioPlayer();
String link;
Duration playerTimeNow = Duration(seconds: 0);
Duration playerLength;
double playerBarValue = 0.0;
Episode episode;
Item podcastInfo;
String episodeName, episodeThumbnail;
bool isPlaying = false;
PlayerProvider() {
updateState();
}
play() async {
print("Started Playing");
// Stop previous playing
player.stop();
playerTimeNow = Duration(seconds: 0);
isPlaying = false;
// link = updateLinkToHttps(link);
print(link);
final audio = Audio.network(
link,
metas: Metas(
title: podcastInfo.collectionName,
artist: podcastInfo.artistName,
album: podcastInfo.trackName,
image: MetasImage.network(podcastInfo.artworkUrl600),
//can be MetasImage.network
),
);
var duration = await player.open(
audio,
showNotification: true,
notificationSettings: NotificationSettings(
//seekBarEnabled: false,
//stopEnabled: true,
//customStopAction: (player){
// player.stop();
//}
//prevEnabled: false,
customNextAction: (player) {
print("next1");
forward();
}, customPrevAction: (player) {
print("next2");
backword();
}
//customStopIcon: AndroidResDrawable(name: "ic_stop_custom"),
//customPauseIcon: AndroidResDrawable(name:"ic_pause_custom"),
//customPlayIcon: AndroidResDrawable(name:"ic_play_custom"),
),
);
isPlaying = true;
// player.play(); // Usually you don't want to wait for playback to finish.
print("started");
setState();
}
pause() async {
await player.pause();
isPlaying = false;
print("paused");
setState();
}
resume() async {
//TODO: Setup resume
await player.seek(playerTimeNow);
player.play();
isPlaying = true;
}
speed(double val) async {
print(val);
//TODO: Setup resume
await player.setPlaySpeed(val);
isPlaying = true;
}
updateState() {
player.currentPosition.listen((event) {
playerTimeNow = event;
updatePlayerBar();
});
}
updatePlayerBar() {
int totalLengthInMilliSeconds = playerLength.inMilliseconds;
int totalPlayedInMilliSeconds = playerTimeNow.inMilliseconds;
double newPlayerBarValue =
totalPlayedInMilliSeconds / totalLengthInMilliSeconds;
playerBarValue = newPlayerBarValue;
// print(playerBarValue);
// print(playerTimeNow);
// print(playerLength);
// print(playerLength);
// if (playerLength == playerTimeNow) {
// print('Finish');
// player.stop();
// }
notifyListeners();
}
forward() async {
//TODO: Check if at-least 10 seconds are left;
if (playerTimeNow + Duration(seconds: 10) < playerLength)
await player.seek(playerTimeNow + Duration(seconds: 10));
else
await player.seek(playerLength);
print("Forwarded 10 seconds");
}
backword() async {
Duration back = playerTimeNow.inSeconds > 10
? playerTimeNow - Duration(seconds: 10)
: Duration(seconds: 0);
await player.seek(back);
print("Backwarded 10 seconds");
}
seekFromBar(double val) async {
double totalMillis = playerLength.inMilliseconds * val;
int newMillis = totalMillis.toInt();
Duration newSeekLocations = Duration(milliseconds: newMillis);
await player.seek(newSeekLocations);
print("Seek from Bar");
}
setState() {
notifyListeners();
}
}
When time is finished of player then it's showing this error on red screen. I need to know the fix of this? Mean when it's finished time go to 0 or something. The issue is on the slider I think because if I back from the red screen then my slider goes to zero.
check thet the value of model.playerBarValue is neither Nan or null, and set a max value for the slider.
Slider(
value: model.playerBarValue.isNaN==true || model.playerBarValue==null? 0 : model.playerBarValue,
min: 0.0,
max: duration.inSeconds.toDouble() + 1.0,
onChanged: (value) {
. . .
},
)

Shared Preferences set null after setting a new value to the key

Am working on the task of changing the user name, however, when I click the button of changing the firstName and lastName, the shared preference is not set. This is my API Provider class am hitting :
class ChangeNameApiProvider {
Future<SharedPreferences> _pref = SharedPreferences.getInstance();
static const String USER = "USER";
// ignore: missing_return
Future<int> changeName(
String firstName, String lastName, String userId) async {
SharedPreferences prefs = await _pref;
String user = prefs.getString(USER);
var _user = jsonDecode(user);
final response = await http.put(
'${BaseUrl.BASE_URL}/v1/Users/$userId',
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ${_user['token']}'
},
body: jsonEncode(<String, String>{
'first_name': firstName,
'last_name': lastName,
}),
);
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
_user['user'] = data;
_pref.then((SharedPreferences sharedPref) {
prefs = sharedPref;
print('after output $_user');
prefs.setString(USER, _user.toString());
print('after 2 output $_user');
});
return response.statusCode;
} else {
return response.statusCode;
}
}
}
Then, this is the Button on the form I trigger to call the above changeName() method :
FlatButton(
// ignore: sdk_version_ui_as_code
onPressed: () async => {
if (_formKey.currentState.validate())
{
changeNameRepository
.editName(_firstNameController.text,
_lastNameController.text, '${widget.userId}')
.then((value) async {
if (value == 200) {
_showToastMessage("Name changed successfully.");
await Navigator.pop(context);
}
})
}
},
child: Text(
'SAVE CHANGES',
textAlign: TextAlign.right,
style: TextStyle(
color: Color(0xFFD2232A),
letterSpacing: 1.25,
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
)
Then, this is the repository :
class ChangeNameRepository {
final changeNameApiProvider = ChangeNameApiProvider();
Future editName(firstName, lastName, userId) =>
changeNameApiProvider.changeName(firstName, lastName, userId);
}
So, when all the above code is executed, it's supposed to update the shared preferences, then pop back to the previous screen with updated Shared Preference vale USER.
But it seems, the value is set to null, it's not updating.
Finally, let me share how I retrieve the shared preferences on the first page after popping from the changing nanme page:
_localStorage() async {
try {
await SharedPreferences.getInstance().then((SharedPreferences prefs) {
preferences = prefs;
_user = preferences.getString(USER).toString();
});
setState(() {
user = jsonDecode(_user);
});
} catch (e) {
log('data: $e');
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
_localStorage();
}
What am I missing?

Can layout and logic separated in flutter?

I understand presence Bloc and Scoped Model in flutter.
But that isn't separate like a layout file in java's SpringBoot.
You can actually separate layout and logic in flutter. I have an example.
In my LoginForm I have a function
_attemptLogin() {
BlocProvider.of<LoginBloc>(context).add(
LoginButtonPressed(
context: context,
email: _tecEmail.text,
password: _tecPassword.text,
),
);
}
called by
RaisedButton(
color: Colors.blue,
child: const Text(
'Login',
style: TextStyle(
color: Colors.white,
),
),
onPressed: (state is LoginProcessing)
? null
: _attemptLogin,
),
and in my LoginBloc, I have the ff code inside mapEventToState
#override
Stream<LoginState> mapEventToState(LoginEvent event) async* {
if (event is LoginButtonPressed) {
yield LoginProcessing();
await Future.delayed(const Duration(milliseconds: 250));
try {
var loginResponse =
await _attemptLogin(userRepository, event.email, event.password);
/// Get Firebase Token
final firebaseToken =
await Provider.of<FirebaseMessagingProvider>(context).getToken();
if (loginResponse['data'] != null && firebaseToken != null) {
User user =
_setUserFromJsonMap(context, loginResponse['data']['user']);
IdentityToken identityToken = _setIdentityTokenFromJsonMap(
context, loginResponse['data']['token']);
/// Request Firebase Token Update
var jsonCreateUserFirebaseTokenResponse =
await _attemptFirebaseTokenUpdate(context, firebaseToken);
if (jsonCreateUserFirebaseTokenResponse != null) {
authBloc.add(LoggedIn(identityToken: identityToken));
yield LoginInitial();
}
} else {
yield LoginFailure(message: 'Login failed.');
}
} catch (error, stackTrace) {
print(error);
print(stackTrace);
await Future.delayed(const Duration(seconds: 1));
yield LoginFailure(
message: 'Login failed. Please check your internet connection.');
}
}
}
I didn't include all the other functions/classes as I have already deleted several lines of code to make it look readable, since it contains a ton of code already; which is unnecessary for only trying to prove a point that you can actually separate code for your view and logic.