Flutter String Problem in equality comparison - flutter

Problem
This is my code in Flutter. As you can see, on line 33 the value of type is 'ngo' as is printed on line 34 using print statement. But, in the if block, the correct block does not get executed. I can't understand what's the issue. Please help.
main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/services.dart';
import 'package:xyz/homescreen.dart';
import 'package:xyz/ngo_details.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
await SystemChrome.setEnabledSystemUIOverlays([]);
var _homeWidget = await checkUserLogin();
//Timer(Duration(seconds: 3), () {runApp(MyApp(rootWidget: _homeWidget));});
runApp(MyApp(rootWidget: _homeWidget));
}
Future<Widget> checkUserLogin() async {
final firestoreInstance = Firestore.instance;
final curUser = await FirebaseAuth.instance.currentUser();
if (curUser != null) {
firestoreInstance
.collection('users')
.document(curUser.uid)
.get()
.then((value) {
if (!value.exists) {
FirebaseAuth.instance.signOut();
return HomeScreen();
} else {
String type = value.data['type'];
print(type);
if (type == 'ngo') {
return NGODetailsScreen(user: curUser);
}
else if (type =='user') {
return NGODetailsScreen(user: curUser);
}
}
print('no cases selected');
return Container(color: Colors.yellow,);
});
} else {
return HomeScreen();
}
print('return outer');
return Container(color: Colors.red,);
}
class MyApp extends StatelessWidget {
final firestoreInstance = Firestore.instance;
final rootWidget;
MyApp({this.rootWidget});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Charity for Everyone',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: rootWidget,
);
}
}
Output :
Expected results: NGODetailsScreen should be called after outputting 'ngo' on line 34
Actual results: Container with red background is executed even when line 34 outputs 'ngo'
Logs
PS D:\flutter\xyz> flutter run
Launching lib\main.dart on Redmi Note 4 in debug mode...
Running Gradle task 'assembleDebug'...
Running Gradle task 'assembleDebug'... Done 16.1s
√ Built build\app\outputs\apk\debug\app-debug.apk.
I/flutter (18833): return outer
W/DynamiteModule(18833): Local module descriptor class for providerinstaller not found.
I/DynamiteModule(18833): Considering local module providerinstaller:0 and remote module providerinstaller:0
W/ProviderInstaller(18833): Failed to load providerinstaller module: No acceptable module found. Local version is 0 and remote version is 0.
W/ResourceType(18833): No package identifier when getting name for resource number 0x00000000
V/NativeCrypto(18833): Registering com/google/android/gms/org/conscrypt/NativeCrypto's 286 native methods...
D/NetworkSecurityConfig(18833): No Network Security Config specified, using platform default
I/ProviderInstaller(18833): Installed default security provider GmsCore_OpenSSL
W/art (18833): Before Android 4.1, method double java.util.concurrent.ThreadLocalRandom.internalNextDouble(double, double) would have incorrectly overridden the package-private method
in java.util.Random
W/art (18833): Before Android 4.1, method int java.util.concurrent.ThreadLocalRandom.internalNextInt(int, int) would have incorrectly overridden the package-private method in java.util.Random
W/art (18833): Before Android 4.1, method long java.util.concurrent.ThreadLocalRandom.internalNextLong(long, long) would have incorrectly overridden the package-private method in java.util.Random
Syncing files to device Redmi Note 4... 1,216ms
Flutter run key commands.
r Hot reload.
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on Redmi Note 4 is available at: http://127.0.0.1:65500/s-e-dD_DnYk=/
I/flutter (18833): ngo
Application finished.
D:\flutter\xyz>flutter analyze
Analyzing xyz...
No issues found! (ran in 22.5s)

Thanks #jamesdlin for pointing out the solution.
Basically I changed
firestoreInstance
.collection('users')
.document(curUser.uid)
.get()
.then((value)
to
var value = await firestoreInstance
.collection('users')
.document(curUser.uid)
.get();
and it worked.

Related

Flutter Riverpod StateNotifier load data after logged in

I am trying initializing themeStateNotifier by fetching data after user logged in, from my code I saw that constructor of themeStateNotifier only initialize once after application starts when I didn't login, even though I add isLoggedIn as dependency.
So what is the solution I can make themeStateNotifier fetching theme data after login?
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:seeder/main.dart';
class ThemeStateNotifier extends StateNotifier<bool> {
final FirebaseAuth auth = FirebaseAuth.instance;
final dbInstance = FirebaseFirestore.instance;
ThemeStateNotifier() : super(false) {
if (auth.currentUser != null) {
var userSettingDoc =
dbInstance.collection('user').doc(auth.currentUser!.uid);
Future theme = userSettingDoc.get().then((value) {
print('theme' + value.toString());
return value['themeMode'];
});
theme.then((value) => print(value));
}
}
void changeTheme() {
state = !state;
String themeMode = state == false ? 'light' : 'dark';
if (auth.currentUser != null) {
var userSettingDoc =
dbInstance.collection('user').doc(auth.currentUser!.uid);
userSettingDoc.set({'themeMode': themeMode});
// print(userSettingDoc);
}
}
}
final themeStateNotifierProvider =
StateNotifierProvider<ThemeStateNotifier, bool>(
(ref) => ThemeStateNotifier(),
dependencies: [isLoggedIn]);
and console didn't print anything when app started up.
Launching lib/main.dart on Chrome in debug mode...
lib/main.dart:1
This app is linked to the debug service: ws://127.0.0.1:64779/Xf5d1A8qvMc=/ws
Debug service listening on ws://127.0.0.1:64779/Xf5d1A8qvMc=/ws
💪 Running with sound null safety 💪
Connecting to VM Service at ws://127.0.0.1:64779/Xf5d1A8qvMc=/ws
Flutter Web Bootstrap: Programmatic
Application finished.
Exited
attached with nisLoggedIn, it works well for all places
final isLoggedIn = StateNotifierProvider<GenericStateNotifier<bool>, bool>(
(ref) => GenericStateNotifier<bool>(false));
and GenericStateNotifier is just a class with getter setter, no worry about it, it always works.
class GenericStateNotifier<V> extends StateNotifier<V> {
GenericStateNotifier(V d) : super(d);
set value(V v) {
state = v;
}
V get value => state;
}

Flutter: Cannot use this MethodChannel before the binary messenger has been initialized when running a function using isolates

I'm trying to use isolates in my Flutter app with Bloc as a state management solution. Right now, I'm running into an error when running a particular function in wallet_list.dart.
// wallet_list.dart
final FlutterSecureStorage _storage = const FlutterSecureStorage();
FutureOr<List<alan.Wallet>> getWalletList(int value) async {
Map<String, String> allValues = await _storage.readAll();
final List<alan.Wallet> _walletList = [];
allValues.forEach((key, value) {
if (key.startsWith(WalletOverviewHomeScreen.walletKey)) {
final arrMnemonic = value.split(' ');
final _wallet = alan.Wallet.derive(arrMnemonic, certikNetworkInfo);
// debugPrint('Adding wallet: $_wallet');
_walletList.add(_wallet);
}
});
The following function is used in one of the methods in the cubit class WalletInitializationCubit.
// inside WalletInitializationCubit
Future<void> getWalletListAndDefaultWallet() async {
try {
debugPrint('WalletListInitialization');
emit(WalletInitializationLoading());
final List<alan.Wallet> walletList = await compute(
getWalletList,
1
);
// other cubit logic
}
When trying to build the app, it returns this error:
Exception has occurred.
_AssertionError ('package:flutter/src/services/platform_channel.dart': Failed assertion:
line 134 pos 7: '_binaryMessenger != null || ServicesBinding.instance != null': Cannot use
this MethodChannel before the binary messenger has been initialized. This happens when you
invoke platform methods before the WidgetsFlutterBinding has been initialized. You can fix
this by either calling WidgetsFlutterBinding.ensureInitialized() before this or by passing
a custom BinaryMessenger instance to MethodChannel().)
For context, the main.dart file looks similar to this.
void main() async {
runApp(
const MyApp(),
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
const MyApp();
#override
Widget build(BuildContext context) {
final ThemeData theme = ThemeData();
return MultiBlocProvider(
providers: [
BlocProvider<WalletInitializationCubit>(
create: (context) => WalletInitializationCubit(),
),
],
child: HomeScreen(),
.....
}
}
The relevant line of code that causes the error is
// in getWalletList function
Map<String, String> allValues = await _storage.readAll();
I've tried adding WidgetsFlutterBinding.ensureInitialized() before that line as so:
// in getWalletList function
WidgetsFlutterBinding.ensureInitialized()
Map<String, String> allValues = await _storage.readAll();
But that would then cause a UI actions are only available on root isolate error.
How can I fix this error? I can't use the usual way of using async and await since the process being ran is rather heavy and causes the app to freeze.
Based on the error UI actions are only available on root isolate it is clear that you cannot execute WidgetsFlutterBinding.ensureInitialized() inside the isolate. Also, as you mentioned in the comments, _storage.readAll() method causes this problem.
Having this in mind, what you could do is run the _storage.readAll() in your main isolate (what's run by the main function) and pass the result to the isolate as a parameter.

Flutter open_file.dart not opening pdf file

Im noob in flutter, i try to recreate this proses,create, save then launch pdf, this app has 2 dart file:
1. main.dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdf/pdf.dart';
import 'mobile.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {...}
class MyHomePage extends StatefulWidget {...}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: Text('Cliick Me'),
onPressed: _createPDF,
),
),
);
}
Future<void> _createPDF() async {
PdfDocument document = PdfDocument();
final page = document.pages.add();
page.graphics.drawString(
'welcome',
PdfStandardFont(PdfFontFamily.helvetica, 30)
);
List<int> bytes = document.save();
document.dispose();
//FileSaveHelper.saveAndLaunchFile(bytes, 'Outfile.pdf');
saveAndLaunchFile(bytes, 'Outfile.pdf');
}
2.mobile.dart
import 'dart:io' as io;
import 'dart:io';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
Future<void> saveAndLaunchFile(List<int> bytes, String fileName) async {
try {
final path = (await getExternalStorageDirectory())!.path;
print('filepath : $path/$fileName');
String data='empty';
print('data pos1= $data');
data = (await io.File('$path/$fileName').exists()).toString();
final file = File('$path/$fileName');
await file.writeAsBytes(
bytes,
flush: true
);
print('data pos2= $data');
OpenFile.open('$path/$fileName');
print('done');
}
catch (e) {
print('error : $e');
}
}
Now when I press 'click me', it does nothing, it supposed to show 'welcome' String from main.dart
the output from mobile.dart are bellow:
Syncing files to device Android SDK built for x86...
Reloaded 1 of 955 libraries in 310ms.
I/flutter ( 3688): filepath : `/storage/emulated/0/Android/data/com.cg2.my_first_try/files/Outfile.pdf`
I/flutter ( 3688): data pos1= empty
I/flutter ( 3688): data pos2= true
I/flutter ( 3688): done
The funny things, the day before, when i first install android studio, flutter and run this program, it was working. Then I updated dependency on yaml file, then on this perticular line on mobile.dart, asking
final path = (await getExternalStorageDirectory()).path; generate error ....potentialy null.
so i change into :
final path = (await getExternalStorageDirectory())!.path;
lastly, iam using ubuntu 20.04, i just need to understand whats going on, is it androdi studio or emulator problem, or do linux need permision to getExternalStorageDirectory. Thanks.
Its seem ths java version that causing this. after googling, it turns out openJdk16 has campatible issues, messing up gradle creation. So i downgrade to 11, so far looks good.
To use jdk 16 you should upgrade to:
android/gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
android/build.gradle
classpath 'com.android.tools.build:gradle:7.0.1'
my jdk
java 16.0.1 2021-04-20
Java(TM) SE Runtime Environment (build 16.0.1+9-24)
Java HotSpot(TM) 64-Bit Server VM (build 16.0.1+9-24, mixed mode, sharing)

error `pumpAndSettle timed out` MAYBE due to riverpod

I'm stuck with a widget test and I could use some help
to reproduce the behavior please run the code sample below
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'home_page.dart';
void main() => runApp(
const ProviderScope(
child: MaterialApp(
home: Material(
child: MyHomePage(),
),
),
),
);
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
extension RoundX on double {
double roundToPrecision(int n) {
final f = pow(10, n);
return (this * f).round() / f;
}
}
final tasksPod = Provider<List<Future<void> Function()>>(
(ref) => [
for (var i = 0; i < 10; ++i)
() async {
await Future.delayed(kThemeAnimationDuration);
}
],
);
final progressPod = Provider.autoDispose<ValueNotifier<double>>((ref) {
final notifier = ValueNotifier<double>(0);
ref.onDispose(notifier.dispose);
return notifier;
});
class MyHomePage extends HookWidget {
const MyHomePage() : super(key: const ValueKey('MyHomePage'));
#override
Widget build(BuildContext context) {
final progress = useProvider(progressPod);
final tasks = useProvider(tasksPod);
useMemoized(() async {
final steps = tasks.length;
if (steps < 1) {
progress.value = 1;
} else {
for (final task in tasks) {
final current = progress.value;
if (current >= 1) {
break;
}
await task();
final value = (current + 1 / steps).roundToPrecision(1);
print('$value');
progress.value = value;
}
}
});
return Center(
child: ValueListenableBuilder<double>(
valueListenable: progress,
child: const FlutterLogo(),
builder: (context, value, child) =>
value < 1 ? const CircularProgressIndicator() : child!,
),
);
}
}
running the app everything is fine
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk... 4.7s
Syncing files to device Pixel 3a... 93ms
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
💪 Running with sound null safety 💪
An Observatory debugger and profiler on Pixel 3a is available at: http://127.0.0.1:36517/50vVndYZ3l4=/
I/flutter (19990): 0.1
I/flutter (19990): 0.2
I/flutter (19990): 0.3
I/flutter (19990): 0.4
I/flutter (19990): 0.5
I/flutter (19990): 0.6
I/flutter (19990): 0.7
The Flutter DevTools debugger and profiler on Pixel 3a is available at: http://127.0.0.1:9101?uri=http%3A%2F%2F127.0.0.1%3A36517%2F50vVndYZ3l4%3D%2F
I/flutter (19990): 0.8
I/flutter (19990): 0.9
I/flutter (19990): 1.0
Application finished.
but fails this test
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:timeout_issue/home_page.dart';
void main() {
testWidgets(
'WHEN tasks are not completed'
'THEN shows `CircularProgressIndicator`', (tester) async {
TestWidgetsFlutterBinding.ensureInitialized();
await tester.runAsync(() async {
await tester.pumpWidget(
ProviderScope(
child: const MaterialApp(
home: Material(
child: MyHomePage(),
),
),
),
);
await tester.pumpAndSettle(kThemeAnimationDuration);
expect(
find.byType(CircularProgressIndicator),
findsOneWidget,
reason: 'CircularProgressIndicator should be shown',
);
});
});
}
with this output
00:05 +0: WHEN tasks are not completedTHEN shows `CircularProgressIndicator`
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown while running async test code:
pumpAndSettle timed out
When the exception was thrown, this was the stack:
#0 WidgetTester.pumpAndSettle.<anonymous closure> (package:flutter_test/src/widget_tester.dart:651:11)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
00:05 +0 -1: WHEN tasks are not completedTHEN shows `CircularProgressIndicator` [E]
Test failed. See exception logs above.
The test description was: WHEN tasks are not completedTHEN shows `CircularProgressIndicator`
00:05 +0 -1: Some tests failed.
the environment is
Flutter version 2.2.0-11.0.pre.176
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
hooks_riverpod: ^0.14.0
flutter_hooks: ^0.16.0
any help is apprecciated
I'd say the problem is related to using pumpAndSettle and an infinite animation (Circular progress indicator).
You can try using pump without the settle to build frames yourself.
https://api.flutter.dev/flutter/flutter_test/WidgetTester/pumpAndSettle.html
It seems atm riverpod and pumpAndSettle are not working, as a nasty quick hack you can try something like this:
for (int i = 0; i < 5; i++) {
// because pumpAndSettle doesn't work with riverpod
await tester.pump(Duration(seconds: 1));
}
#zuldyc is correct. By running the step asynchronously, it gives the Timer what it needs to finish successfully before continuing. I've got a working example now that will hopefully make things more clear.
BROKEN CODE
testWidgets('Testing Login Button Success - New User', (tester) async {
final amplifyAuthMock = MockAmplifyAuth();
final dbInterfaceMock = MockDatabaseInterface();
when(amplifyAuthMock.login('testNew#test.com', 'password!'))
.thenAnswer((result) async => true);
when(dbInterfaceMock.startStopDBSync())
.thenAnswer((realInvocation) async => true);
when(dbInterfaceMock.restartDBSync())
.thenAnswer((realInvocation) async => true);
// CREATING FORM TO TEST
await tester
.pumpWidget(createLoginForm(amplifyAuthMock, dbInterfaceMock));
await inputDummyLoginText(tester, email: 'testNew#test.com');
// PRESSING LOGIN BUTTON AND SHOULD GO TO HOME PAGE
await tester.tap(find.byType(SkillTreeElevatedButton));
// BREAKS HERE ON PUMP AND SETTLE******
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
It breaks because of the reasons described in accepted answer. Well, sort of. You get a sort of race condition because we are using a future which is asynchronous, but the code above doesn't account for that so it executes the future widget's code but does not know to wait for it to finish creating, so it exists and everything explodes. We need to make the ENTIRE process asynchronous. We do this by following Zuldyc's answer. By changing my code to the following it works without issue
// THE ABOVE CODE HAS NOT CHANGED, NEW CODE STARTS HERE
await tester
.runAsync(() => tester.tap(find.byType(SkillTreeElevatedButton)));
await tester.pump(const Duration(seconds: 1));
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
To be clear the change is as follows
//BEFORE
await tester.tap(find.byType(SkillTreeElevatedButton));
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.byType(CircularProgressIndicator), findsOneWidget);
//AFTER
await tester.runAsync(() => tester.tap(find.byType(SkillTreeElevatedButton)));
await tester.pump(const Duration(seconds: 1));
expect(find.byType(CircularProgressIndicator), findsOneWidget);
My tap action was triggering the new screen and the loading indicator, so i needed to make that action async so that it could finish.
it seems runAsync solves the issue
await tester.runAsync(() => tester.pumpWidget(
ProviderScope(child: MyApp()), const Duration(milliseconds: 100)));
final indicator = const CircularProgressIndicator();
await tester.pumpWidget(indicator);
expect(find.byWidget(indicator), findsOneWidget);

How to run some dart code in the background, every 15 seconds

I've created app that checks the call log list every 15 seconds. I have used Timer.periodic() to achieve this. And everything works fine but only if app is not running in the background. After couple of minutes when app is in the background, the task which is scheduled by Timer.periodic is not executing anymore. I have tried to use android_alarm_manager https://pub.dev/packages/android_alarm_manager but it doesn't work at all. It's logging /FlutterBackgroundExecutor(11431): Starting AlarmService... but then nothing happends.
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:android_alarm_manager/android_alarm_manager.dart';
void main() async{
await WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(MyApp());
final int helloAlarmID = 0;
await AndroidAlarmManager.periodic(Duration(seconds: 5), helloAlarmID, printHello);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
void printHello() {
final DateTime now = DateTime.now();
final int isolateId = Isolate.current.hashCode;
print("[$now] Hello, world! isolate=${isolateId} function='$printHello'");
}
Do I have any other possibilities to reach my goal ?
Android limits background usage to every 15 minutes or so. There are several packages on pub.dev that can run code in background even when the application is closed. However i don't think any of them can run your code every 15 seconds.
Packages include:
background_fetch
workmanager
flutter_background_service
There are several more.