profile
viewpoint
John M. Wargo johnwargo Oracle Charlotte, NC www.johnwargo.com Product Manager, software developer, writer, presenter, husband, father, geek. Interested in all types of technology, especially when they let me write code.

johnwargo/apache-cordova-api-cookbook-code 35

Source code for Apache Cordova API Cookbook

johnwargo/cordova-programming-code 26

Source code from Apache Cordova 3 Programming

johnwargo/ac4p 16

Source code from Apache Cordova 4 Programming

johnwargo/flutter-android-connectivity-permissions 3

An app that demonstrates how to prompt the user for location permissions in Flutter on Android.

johnwargo/Arduino-Twinkle-Lights 2

An Arduino application for fading two strands of LED Lights up and down.

johnwargo/Arduino-Twinkle-Lights-Array 1

A version of the Arduino Twinkle Lights code that supports more than two strands of lights.

johnwargo/firebase-functions-deploy-helper 1

Simplifies deployment of a subset of Firebase Functions (because of Firebase deployment quota limits)

johnwargo/hackspace-article-code 1

Source code for my Hackspace Magazine articles

johnwargo/ics-update 1

A Node module for updating an .ics file and launching it

johnwargo/Arduino-Pinewood-Derby 0

Source code for the Arduino Powered Pinewood Derby project.

push eventjohnwargo/spinner-circuit-playground

John M. Wargo

commit sha 7bd2c582c72e2edf071f235fb259b938a511826a

Update spinner-circuit-playground.ino Added variable to control whether changing direction also resets the speed

view details

push time in a month

pull request commentjohnwargo/seeed-studio-relay-board

Added modified library for remote usage over ethernet

@itskolby thanks for the PR, but you didn't provide any description or justification for why this should be included in the library. It looks to me like you modified the library for your specific use case which doesn't align with the purpose for the library. There is no need to modify the library to enable remote access - it's a stand alone library that does one thing and one thing only - interact locally with the relay hardware.

If you want to be able to remotely control the relay, use this library in an application that listens for network connections and acts accordingly.

itskolby

comment created time in a month

push eventjohnwargo/spinner-circuit-playground

John M. Wargo

commit sha 2b4d0cbb24f35b54e045f9b03884b9f588954f21

Update spinner-circuit-playground.ino

view details

push time in a month

push eventjohnwargo/spinner-circuit-playground

John M. Wargo

commit sha 28fe22e2d83cd55f1e74ac4fc65dc4b2658778bc

Update spinner-circuit-playground.ino

view details

push time in a month

PublicEvent

push eventjohnwargo/spinner-circuit-playground

John M. Wargo

commit sha c97835fc424e96ab55c7450d9df0001d8e420c4a

Update spinner-circuit-playground.ino

view details

push time in a month

push eventjohnwargo/spinner-circuit-playground

John M. Wargo

commit sha 7937b6aabfe9ba6fd8da60d32233062469497d96

Update spinner-circuit-playground.ino added debouncing note plus shortened some of the debug code

view details

push time in a month

issue commentFirebaseExtended/flutterfire

🐛 Firebase_Database Assertion error on push for sorted FirebaseAnimatedList

@lesnitsky can you please provide more detail? Dropped when? Successor implemented when? Is the team going to fix this now or do we have to wait for firebase_UI?

We're trying to get this working in the apps we have now, so future plans don't help us very much without the right context.

johnwargo

comment created time in a month

PublicEvent

push eventjohnwargo/begin-hello-world-app

Begin

commit sha 5b1e27a58b7c34d580efbe9ec1cb7bc3ec006fa7

ci: so it Begins!

view details

push time in 2 months

create barnchjohnwargo/begin-hello-world-app

branch : main

created branch time in 2 months

created repositoryjohnwargo/begin-hello-world-app

Begin app

created time in 2 months

created tagjohnwargo/begin-react-app

tag0.0.1

Begin app

created time in 2 months

release johnwargo/begin-react-app

0.0.1

released time in 2 months

issue commentFirebaseExtended/flutterfire

🐛 Firebase_Database Assertion error on push for sorted FirebaseAnimatedList

My sincerest and most humble apologies for not delivering the smallest possible sample, I didn't know whether the issue was caused by Analytics or Crashes, so I left them in there. Here's a single file you can copy into a project's main.dart.

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
// import 'package:firebase_analytics/firebase_analytics.dart';
// import 'package:firebase_crashlytics/firebase_crashlytics.dart';
// import 'package:firebase_analytics/observer.dart';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:intl/intl.dart';
import 'package:random_string/random_string.dart';

const appName = 'Flutter Firebase Demo';
final GoogleSignIn _googleSignIn = GoogleSignIn();
late Future initFuture;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Future<void> _initializeFlutterFireFuture;

  // Future<void> _testAsyncErrorOnInit() async {
  //   Future<void>.delayed(const Duration(seconds: 2), () {
  //     final List<int> list = <int>[];
  //     print(list[100]);
  //   });
  // }

  // Define an async function to initialize FlutterFire
  // Future<void> _initializeFlutterFire() async {
  //   // Wait for Firebase to initialize
  //
  //   if (_kTestingCrashlytics) {
  //     // Force enable crashlytics collection enabled if we're testing it.
  //     await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
  //   } else {
  //     // Else only enable it in non-debug builds.
  //     // You could additionally extend this to allow users to opt-in.
  //     await FirebaseCrashlytics.instance
  //         .setCrashlyticsCollectionEnabled(!kDebugMode);
  //   }
  //
  //   // Pass all uncaught errors to Crashlytics.
  //   Function originalOnError = FlutterError.onError as Function;
  //
  //   FlutterError.onError = (FlutterErrorDetails errorDetails) async {
  //     await FirebaseCrashlytics.instance.recordFlutterError(errorDetails);
  //     // Forward to original handler.
  //     originalOnError(errorDetails);
  //   };
  //
  //   if (_kShouldTestAsyncErrorOnInit) {
  //     await _testAsyncErrorOnInit();
  //   }
  // }

  // @override
  // void initState() {
  //   super.initState();
  //   _initializeFlutterFireFuture = _initializeFlutterFire();
  // }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: appName,
        debugShowCheckedModeBanner: false,
        theme: ThemeData.light(),
        darkTheme: ThemeData.dark(),
        home: FirebaseDemoHome(title: appName));
  }
}

class FirebaseDemoHome extends StatefulWidget {
  const FirebaseDemoHome({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<FirebaseDemoHome> createState() => _FirebaseDemoHomeState();
}

class _FirebaseDemoHomeState extends State<FirebaseDemoHome> {
  late DatabaseReference _recordsRef;
  late StreamSubscription<Event> _recordsSubscription;
  late bool isLoggedIn;

  final ScrollController _scrollController = ScrollController();

  Future<UserCredential> _signInWithGoogle() async {
    // Trigger the authentication flow
    final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
    // Obtain the auth details from the request
    final GoogleSignInAuthentication googleAuth =
        await googleUser!.authentication;
    // Create a new credential
    final credential = GoogleAuthProvider.credential(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );
    // Once signed in, return the UserCredential
    return await FirebaseAuth.instance.signInWithCredential(credential);
  }

  _doLogin() {
    _signInWithGoogle().then((UserCredential theUser) {
      print("UID: ${theUser.user!.uid}");
      setState(() {
        isLoggedIn = theUser.user!.uid.isNotEmpty;
      });
    });
  }

  _doLogout() {
    // logs out of Firebase and Google
    FirebaseAuth.instance.signOut().then((value) {
      _googleSignIn.disconnect();
      setState(() {
        isLoggedIn = (FirebaseAuth.instance.currentUser != null);
      });
    }).catchError((error) {
      print("Unable to logout");
      print(error);
    });
  }

  // https://www.raywenderlich.com/24346128-firebase-realtime-database-tutorial-for-flutter
  Query getRecordsQuery() {
    return _recordsRef;
  }

  // Initialize the Config class (loading data) for the FutureBuilder
  Future<bool> initializeApp() async {
    print('HomePage: initializeApp()');
    // Initialize the Records database (Firebase)
    _recordsRef = FirebaseDatabase.instance.reference().child('records');
    FirebaseAuth.instance.authStateChanges().listen((User? user) {
      print("Auth State Change detected");
      if (user == null) {
        print('User is currently signed out!');
        try {
          // Cancel the records subscription (if we have one)
          _recordsSubscription.cancel();
        } catch (e) {}
      } else {
        print('User is signed in!');
        // setup the home page data listener
        _recordsSubscription = _recordsRef.onValue.listen((Event event) {
          print('Records: ${event.snapshot.value.toString()}');
        }); // Tell FutureBuilder we're ready to go...
      }
    });
    return true;
  }

  void _addRecord() async {
    late String userName;
    print("Adding record");
    userName = 'Unknown';
    // TODO: Fix this ASAP
    // All this does is prove that I don't truly understand null safety
    // in Dart/Flutter
    if (FirebaseAuth.instance.currentUser != null) {
      if (FirebaseAuth.instance.currentUser!.displayName != null) {
        userName = FirebaseAuth.instance.currentUser!.displayName!;
      }
    }
    Record record = Record(randomAlphaNumeric(20), userName,
        DateTime.now().millisecondsSinceEpoch);
    try {
      await _recordsRef.push().set(record.toJson());
    } catch (e) {
      print("Error: $e");
    }
  }

  @override
  void initState() {
    print('HomePage: initState()');
    isLoggedIn = false;
    super.initState();
    initFuture = initializeApp();
  }

  Widget recordList() {
    final DateFormat formatter = DateFormat('yyyy-MM-dd @ hh:mm:ss');

    return FirebaseAnimatedList(
      controller: _scrollController,
      query: getRecordsQuery(),
      // https://stackoverflow.com/questions/69377110/flutter-firebaseanimatedlist-assertion-error-on-push-in-sorted-list
      // https://github.com/FirebaseExtended/flutterfire/issues/7100
      sort: (a, b) {
        return a.value['timestamp'].compareTo(b.value['timestamp']);
      },
      itemBuilder: (context, snapshot, animation, index) {
        final json = snapshot.value as Map<dynamic, dynamic>;
        final record = Record.fromJson(json);
        var date = DateTime.fromMicrosecondsSinceEpoch(record.timestamp * 1000);
        return ListTile(
          title: Text("Message: ${record.msg}"),
          subtitle: Text("${record.user} (${formatter.format(date)}))"),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: initFuture,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            if (isLoggedIn) {
              return Scaffold(
                appBar: AppBar(title: Text(widget.title), actions: <Widget>[
                  IconButton(
                    icon: const Icon(Icons.logout_outlined),
                    onPressed: _doLogout,
                  ),
                ]),
                body: SafeArea(child: recordList()),
                floatingActionButton: FloatingActionButton(
                  onPressed: _addRecord,
                  tooltip: 'Add Record',
                  child: const Icon(Icons.add),
                ),
              );
            } else {
              return Scaffold(
                  appBar: AppBar(
                    title: Text(widget.title),
                  ),
                  body: SafeArea(
                      child: ListView(
                          padding: const EdgeInsets.all(16.0),
                          children: [
                        const Text(
                            "Access to this application is restricted to Authorized users only."),
                        const SizedBox(height: 15),
                        ConstrainedBox(
                          constraints: const BoxConstraints.tightFor(
                              width: 300, height: 75),
                          child: ElevatedButton(
                            child: const Text('Login'),
                            onPressed: _doLogin,
                          ),
                        )
                      ])));
            }
          } else {
            // Display the initialization message
            return Scaffold(
                appBar: AppBar(title: Text(widget.title)),
                body: const SafeArea(
                    child: Center(child: Text('Reading application data'))));
          } // if (!snapshot.hasData)
        });
  }
}

class Record {
  final String msg;
  final String user;
  final int timestamp;

  Record(this.msg, this.user, this.timestamp);

  Record.fromJson(Map<dynamic, dynamic> json)
      : msg = json['msg'],
        user = json['user'],
        timestamp = json['timestamp'];

  Map<dynamic, dynamic> toJson() =>
      {'msg': msg, 'user': user, 'timestamp': timestamp};
}

When I try to add a document to the collection with the sort in place, it crashes with the following error:

I/flutter (17228): Adding record
E/flutter (17228): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: 'package:flutter/src/widgets/animated_list.dart': Failed assertion: line 959 pos 12: 'index != null && index >= 0': is not true.
E/flutter (17228): #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39)
E/flutter (17228): #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5)
E/flutter (17228): #2      SliverAnimatedListState.insertItem (package:flutter/src/widgets/animated_list.dart:959:12)
E/flutter (17228): #3      AnimatedListState.insertItem (package:flutter/src/widgets/animated_list.dart:484:42)
E/flutter (17228): #4      FirebaseAnimatedListState._onChildAdded (package:firebase_database/ui/firebase_animated_list.dart:175:36)
E/flutter (17228): #5      FirebaseSortedList._onChildAdded (package:firebase_database/ui/firebase_sorted_list.dart:97:18)
E/flutter (17228): #6      _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter (17228): #7      _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (17228): #8      _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (17228): #9      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (17228): #10     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter (17228): #11     _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
E/flutter (17228): #12     _MapStream._handleData (dart:async/stream_pipe.dart:218:10)
E/flutter (17228): #13     _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
E/flutter (17228): #14     _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter (17228): #15     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (17228): #16     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (17228): #17     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (17228): #18     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter (17228): #19     _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
E/flutter (17228): #20     _HandleErrorStream._handleData (dart:async/stream_pipe.dart:253:10)
E/flutter (17228): #21     _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
E/flutter (17228): #22     _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter (17228): #23     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (17228): #24     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (17228): #25     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (17228): #26     _DelayedData.perform (dart:async/stream_impl.dart:591:14)
E/flutter (17228): #27     _StreamImplEvents.handleNext (dart:async/stream_impl.dart:706:11)
E/flutter (17228): #28     _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:663:7)
E/flutter (17228): #29     _rootRun (dart:async/zone.dart:1420:47)
E/flutter (17228): #30     _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter (17228): #31     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter (17228): #32     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter (17228): #33     _rootRun (dart:async/zone.dart:1428:13)
E/flutter (17228): #34     _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter (17228): #35     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter (17228): #36     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter (17228): #37     _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
E/flutter (17228): #38     _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)

If I comment out the sort, it works as expected.

I left the login details in there, because the whole point of this partcular application is to use Auth and Realtime database and my Firebase project has the following realtime database access rules:

{
  "rules": {
     "records": {
        ".read": "auth != null",
        ".write": "auth != null"
    }
  }
}

but that shouldn't affect the operation of the sort method.

johnwargo

comment created time in 2 months

push eventjohnwargo/begin-react-app

Begin

commit sha 9386a15d9156e67ed06d595070c161aa48d2278e

ci: so it Begins!

view details

push time in 2 months

create barnchjohnwargo/begin-react-app

branch : main

created branch time in 2 months

created repositoryjohnwargo/begin-react-app

Begin app

created time in 2 months

issue commentFirebaseExtended/flutterfire

🐛 Firebase_Database Assertion error on push for sorted FirebaseAnimatedList

@markusaksli-nc here ya go:

my main.dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:firebase_analytics/observer.dart';

import 'pages/home.dart';

// Toggle this to cause an async error to be thrown during initialization
// and to test that runZonedGuarded() catches the error
const _kShouldTestAsyncErrorOnInit = false;

// Toggle this for testing Crashlytics in your app locally.
const _kTestingCrashlytics = true;

const appName = 'Flutter Firebase Demo';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  // runApp(const MyApp());
  runZonedGuarded(() {
    runApp(MyApp());
  }, FirebaseCrashlytics.instance.recordError);
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  static FirebaseAnalytics analytics = FirebaseAnalytics();
  static FirebaseAnalyticsObserver observer =
      FirebaseAnalyticsObserver(analytics: analytics);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Future<void> _initializeFlutterFireFuture;

  Future<void> _testAsyncErrorOnInit() async {
    Future<void>.delayed(const Duration(seconds: 2), () {
      final List<int> list = <int>[];
      print(list[100]);
    });
  }

  // Define an async function to initialize FlutterFire
  Future<void> _initializeFlutterFire() async {
    // Wait for Firebase to initialize

    if (_kTestingCrashlytics) {
      // Force enable crashlytics collection enabled if we're testing it.
      await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
    } else {
      // Else only enable it in non-debug builds.
      // You could additionally extend this to allow users to opt-in.
      await FirebaseCrashlytics.instance
          .setCrashlyticsCollectionEnabled(!kDebugMode);
    }

    // Pass all uncaught errors to Crashlytics.
    Function originalOnError = FlutterError.onError as Function;

    FlutterError.onError = (FlutterErrorDetails errorDetails) async {
      await FirebaseCrashlytics.instance.recordFlutterError(errorDetails);
      // Forward to original handler.
      originalOnError(errorDetails);
    };

    if (_kShouldTestAsyncErrorOnInit) {
      await _testAsyncErrorOnInit();
    }
  }

  @override
  void initState() {
    super.initState();
    _initializeFlutterFireFuture = _initializeFlutterFire();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: appName,
      debugShowCheckedModeBanner: false,
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      home: FirebaseDemoHome(
        title: appName,
        analytics: MyApp.analytics,
        observer: MyApp.observer,
      ),
      navigatorObservers: [
        FirebaseAnalyticsObserver(analytics: MyApp.analytics),
      ],
    );
  }
}

and home.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_analytics/observer.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:intl/intl.dart';
import 'package:random_string/random_string.dart';

final GoogleSignIn _googleSignIn = GoogleSignIn();
late Future initFuture;

class FirebaseDemoHome extends StatefulWidget {
  const FirebaseDemoHome({
    Key? key,
    required this.title,
    required this.analytics,
    required this.observer,
  }) : super(key: key);

  final String title;
  final FirebaseAnalytics analytics;
  final FirebaseAnalyticsObserver observer;

  @override
  State<FirebaseDemoHome> createState() => _FirebaseDemoHomeState();
}

class _FirebaseDemoHomeState extends State<FirebaseDemoHome> {
  late DatabaseReference _recordsRef;
  late StreamSubscription<Event> _recordsSubscription;
  late bool isLoggedIn;

  final ScrollController _scrollController = ScrollController();

  Future<UserCredential> _signInWithGoogle() async {
    // move this into the login method
    print("Signing-in with Google");
    await widget.analytics.logEvent(name: "login");
    // Trigger the authentication flow
    final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
    print("signed in");
    // Obtain the auth details from the request
    final GoogleSignInAuthentication googleAuth =
        await googleUser!.authentication;
    print("got auth details");
    // Create a new credential
    final credential = GoogleAuthProvider.credential(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );
    print("got credentials, executing Firebase sign-in");
    // Once signed in, return the UserCredential
    return await FirebaseAuth.instance.signInWithCredential(credential);
  }

  _doLogin() {
    print('Home: Login button tapped');
    _signInWithGoogle().then((UserCredential theUser) {
      print("UID: ${theUser.user!.uid}");
      setState(() {
        isLoggedIn = theUser.user!.uid.isNotEmpty;
      });
    });
  }

  _doLogout() {
    // logs out of Firebase and Google
    print('Home: Logout button tapped');
    FirebaseAuth.instance.signOut().then((value) {
      _googleSignIn.disconnect();
      setState(() {
        isLoggedIn = (FirebaseAuth.instance.currentUser != null);
      });
    }).catchError((error) {
      print("Unable to logout");
      print(error);
    });
  }

  // https://www.raywenderlich.com/24346128-firebase-realtime-database-tutorial-for-flutter
  Query getRecordsQuery() {
    return _recordsRef;
  }

  // Initialize the Config class (loading data) for the FutureBuilder
  Future<bool> initializeApp() async {
    print('HomePage: initializeApp()');
    // Initialize the Records database (Firebase)
    _recordsRef = FirebaseDatabase.instance.reference().child('records');
    FirebaseAuth.instance.authStateChanges().listen((User? user) {
      print("Auth State Change detected");
      if (user == null) {
        print('User is currently signed out!');
        try {
          // Cancel the records subscription (if we have one)
          _recordsSubscription.cancel();
        } catch (e) {}
      } else {
        print('User is signed in!');
        // setup the home page data listener
        _recordsSubscription = _recordsRef.onValue.listen((Event event) {
          print('Records: ${event.snapshot.value.toString()}');
        }); // Tell FutureBuilder we're ready to go...
      }
    });
    return true;
  }

  void _addRecord() async {
    late String userName;
    print("Adding record");
    userName = 'Unknown';
    // TODO: Fix this ASAP
    // All this does is prove that I don't truly understand null safety
    // in Dart/Flutter
    if (FirebaseAuth.instance.currentUser != null) {
      if (FirebaseAuth.instance.currentUser!.displayName != null) {
        userName = FirebaseAuth.instance.currentUser!.displayName!;
      }
    }
    Record record = Record(randomAlphaNumeric(20), userName,
        DateTime.now().millisecondsSinceEpoch);
    try {
      await _recordsRef.push().set(record.toJson());
    } catch (e) {
      print("Error: $e");
    }
  }

  @override
  void initState() {
    print('HomePage: initState()');
    isLoggedIn = false;
    super.initState();
    initFuture = initializeApp();
  }

  Widget recordList() {
    final DateFormat formatter = DateFormat('yyyy-MM-dd @ hh:mm:ss');

    return FirebaseAnimatedList(
      controller: _scrollController,
      query: getRecordsQuery(),
      // https://stackoverflow.com/questions/69377110/flutter-firebaseanimatedlist-assertion-error-on-push-in-sorted-list
      // https://github.com/FirebaseExtended/flutterfire/issues/7100
      sort: (a, b) {
        return a.value['timestamp'].compareTo(b.value['timestamp']);
      },
      itemBuilder: (context, snapshot, animation, index) {
        final json = snapshot.value as Map<dynamic, dynamic>;
        final record = Record.fromJson(json);
        var date = DateTime.fromMicrosecondsSinceEpoch(record.timestamp * 1000);
        return ListTile(
          title: Text("Message: ${record.msg}"),
          subtitle: Text("${record.user} (${formatter.format(date)}))"),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: initFuture,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            if (isLoggedIn) {
              return Scaffold(
                appBar: AppBar(title: Text(widget.title), actions: <Widget>[
                  IconButton(
                    icon: const Icon(Icons.logout_outlined),
                    onPressed: _doLogout,
                  ),
                ]),
                body: SafeArea(child: recordList()),
                floatingActionButton: FloatingActionButton(
                  onPressed: _addRecord,
                  tooltip: 'Add Record',
                  child: const Icon(Icons.add),
                ),
              );
            } else {
              return Scaffold(
                  appBar: AppBar(
                    title: Text(widget.title),
                  ),
                  body: SafeArea(
                      child: ListView(
                          padding: const EdgeInsets.all(16.0),
                          children: [
                        const Text(
                            "Access to this application is restricted to Authorized users only."),
                        const SizedBox(height: 15),
                        ConstrainedBox(
                          constraints: const BoxConstraints.tightFor(
                              width: 300, height: 75),
                          child: ElevatedButton(
                            child: const Text('Login'),
                            onPressed: _doLogin,
                          ),
                        )
                      ])));
            }
          } else {
            // Display the initialization message
            return Scaffold(
                appBar: AppBar(title: Text(widget.title)),
                body: const SafeArea(
                    child: Center(child: Text('Reading application data'))));
          } // if (!snapshot.hasData)
        });
  }
}

class Record {
  final String msg;
  final String user;
  final int timestamp;

  Record(this.msg, this.user, this.timestamp);

  Record.fromJson(Map<dynamic, dynamic> json)
      : msg = json['msg'],
        user = json['user'],
        timestamp = json['timestamp'];

  Map<dynamic, dynamic> toJson() =>
      {'msg': msg, 'user': user, 'timestamp': timestamp};
}
johnwargo

comment created time in 2 months

issue commentflutter/flutter

Discourage committing the current composing region when there's an open input connection

@LongCatIsLooong the problem is not fixed. Please do not make assumptions before closing an issue that a lot of people are having trouble with. I provided a complete sample above that you can use to validate your assumption before closing the issue. I just ran it and the issue persists:

I/flutter ( 6938): Listener fired t
I/flutter ( 6938): Listener fired t
I/flutter ( 6938): Listener fired th
I/flutter ( 6938): Listener fired th
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired th
I/chatty  ( 6938): uid=10155(com.johnwargo.textfield_test) 1.ui identical 1 line
I/flutter ( 6938): Listener fired th
I/flutter ( 6938): Listener fired thi
I/flutter ( 6938): Listener fired thi
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired thi
I/flutter ( 6938): Listener fired thi
I/flutter ( 6938): Listener fired thi
I/flutter ( 6938): Listener fired this
I/flutter ( 6938): Listener fired this
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired this
I/chatty  ( 6938): uid=10155(com.johnwargo.textfield_test) 1.ui identical 1 line
I/flutter ( 6938): Listener fired this
I/flutter ( 6938): Listener fired this 
I/flutter ( 6938): Listener fired this 
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired this i
I/flutter ( 6938): Listener fired this i
I/flutter ( 6938): Listener fired this is
I/flutter ( 6938): Listener fired this is
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired this is
I/flutter ( 6938): Listener fired this is
I/flutter ( 6938): Listener fired this is
I/flutter ( 6938): Listener fired this is 
I/flutter ( 6938): Listener fired this is 
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired this is a
I/flutter ( 6938): Listener fired this is a
I/flutter ( 6938): Listener fired this is a 
I/flutter ( 6938): Listener fired this is a 
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired this is a t
I/flutter ( 6938): Listener fired this is a t
I/flutter ( 6938): Listener fired this is a te
I/flutter ( 6938): Listener fired this is a te
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired this is a te
I/flutter ( 6938): Listener fired this is a te
I/flutter ( 6938): Listener fired this is a te
I/flutter ( 6938): Listener fired this is a tes
I/flutter ( 6938): Listener fired this is a tes
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
I/flutter ( 6938): Listener fired this is a tes
I/flutter ( 6938): Listener fired this is a tes
I/flutter ( 6938): Listener fired this is a tes
I/flutter ( 6938): Listener fired this is a test
I/flutter ( 6938): Listener fired this is a test
I/TextInputPlugin( 6938): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 6938): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 6938): endBatchEdit on inactive InputConnection
I/flutter ( 6938): Listener fired this is a test
I/chatty  ( 6938): uid=10155(com.johnwargo.textfield_test) 1.ui identical 1 line
I/flutter ( 6938): Listener fired this is a test

The listener fires multiple times for every character input.

It doesn't do it on a physical device and the IInoputConnectionWrapper messages only end up on the console once:

Launching lib\main.dart on Pixel 5 in debug mode...
Running Gradle task 'assembleDebug'...
√  Built build\app\outputs\flutter-apk\app-debug.apk.
Installing build\app\outputs\flutter-apk\app.apk...
W/FlutterActivityAndFragmentDelegate(23441): A splash screen was provided to Flutter, but this is deprecated. See flutter.dev/go/android-splash-migration for migration steps.
Debug service listening on ws://127.0.0.1:53174/Y1pFAtLihNk=/ws
Syncing files to device Pixel 5...
I/flutter (23441): Listener fired 
W/IInputConnectionWrapper(23441): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper(23441): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(23441): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper(23441): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(23441): endBatchEdit on inactive InputConnection
W/IInputConnectionWrapper(23441): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper(23441): endBatchEdit on inactive InputConnection
W/IInputConnectionWrapper(23441): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper(23441): endBatchEdit on inactive InputConnection
I/flutter (23441): Listener fired t
I/flutter (23441): Listener fired th
I/flutter (23441): Listener fired thi
I/flutter (23441): Listener fired this
I/flutter (23441): Listener fired this 
I/flutter (23441): Listener fired this i
I/flutter (23441): Listener fired this is
I/flutter (23441): Listener fired this is 
I/flutter (23441): Listener fired this is a
I/flutter (23441): Listener fired this is a 
I/flutter (23441): Listener fired this is a t
I/flutter (23441): Listener fired this is a te
I/flutter (23441): Listener fired this is a tes
I/flutter (23441): Listener fired this is a test

The duplicate listener fires are for the space key I pressed between words.

LongCatIsLooong

comment created time in 2 months

issue openedFirebaseExtended/flutterfire

🐛 Firebase_Database Assertion error on push for sorted FirebaseAnimatedList

Bug report

Describe the bug I build a Flutter application using the firebase database plugin against the Firebase Realtime Database. I'm using the FirebaseAnimatedList to render the documents from a collection and when I add a sort to the FirebaseAnimatedList, I get an assertion error whenever I add a new document to the collection using _recordsRef.push().set(record.toJson());

Here's the error I get from Crashalytics:

----------------FIREBASE CRASHLYTICS----------------
I/flutter (15125): 'package:flutter/src/widgets/animated_list.dart': Failed assertion: line 959 pos 12: 'index != null && index >= 0': is not true.
I/flutter (15125): #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39)
I/flutter (15125): #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5)
I/flutter (15125): #2      SliverAnimatedListState.insertItem (package:flutter/src/widgets/animated_list.dart:959:12)
I/flutter (15125): #3      AnimatedListState.insertItem (package:flutter/src/widgets/animated_list.dart:484:42)
I/flutter (15125): #4      FirebaseAnimatedListState._onChildAdded (package:firebase_database/ui/firebase_animated_list.dart:175:36)
I/flutter (15125): #5      FirebaseSortedList._onChildAdded (package:firebase_database/ui/firebase_sorted_list.dart:97:18)
I/flutter (15125): #6      _rootRunUnary (dart:async/zone.dart:1436:47)
I/flutter (15125): #7      _CustomZone.runUnary (dart:async/zone.dart:1335:19)
I/flutter (15125): #8      _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
I/flutter (15125): #9      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
I/flutter (15125): #10     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
I/flutter (15125): #11     _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
I/flutter (15125): #12     _MapStream._handleData (dart:a
I/flutter (15125): ----------------------------------------------------

When I comment out the sort everything works as expected

Steps to reproduce

Create an app with the plugin. Create a document list using:

Widget recordList() {
    final DateFormat formatter = DateFormat('yyyy-MM-dd @ hh:mm:ss');

    return FirebaseAnimatedList(
      controller: _scrollController,
      query: getRecordsQuery(),
      sort: (a, b) {
        return a.value['timestamp'].compareTo(b.value['timestamp']);
      },
      itemBuilder: (context, snapshot, animation, index) {
        final json = snapshot.value as Map<dynamic, dynamic>;
        final record = Record.fromJson(json);
        var date = DateTime.fromMicrosecondsSinceEpoch(record.timestamp * 1000);
        return ListTile(
          title: Text("Message: ${record.msg}"),
          subtitle: Text("${record.user} (${formatter.format(date)}))"),
        );
      },
    );
  }

add a document to the collection using:

_recordsRef.push().set(record.toJson());

my record looks like this:

class Record {
  final String msg;
  final String user;
  final int timestamp;

  Record(this.msg, this.user, this.timestamp);

  Record.fromJson(Map<dynamic, dynamic> json)
      : msg = json['msg'],
        user = json['user'],
        timestamp = json['timestamp'];

  Map<dynamic, dynamic> toJson() =>
      {'msg': msg, 'user': user, 'timestamp': timestamp};
}

Expected behavior

Its an assertion error, so I assume something's going on inside the package. I expect there to be no assertion errors when I insert a document into the collection while using an FirebaseAnimatedList with a sort method.

Sample project

Providing a minimal example project which demonstrates the bug in isolation from your main App greatly enhances the chance of a timely fix. Please link to the public repository URL.


Additional context

Add any other context about the problem here.


Flutter doctor

Run flutter doctor and paste the output below:

<details><summary>Click To Expand</summary>

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.5.1, on macOS 11.6 20G165 darwin-x64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.60.2)
[✓] Connected device (2 available)

• No issues found!

</details>


Flutter dependencies

Run flutter pub deps -- --style=compact and paste the output below:

<details><summary>Click To Expand</summary>

Dart SDK 2.14.2
Flutter SDK 2.5.1
fb_demo_flutter 1.0.0+1

dependencies:
- firebase_analytics 8.3.2 [firebase_analytics_platform_interface firebase_analytics_web firebase_core flutter meta]
- firebase_auth 3.1.1 [firebase_auth_platform_interface firebase_auth_web firebase_core firebase_core_platform_interface flutter meta]
- firebase_core 1.6.0 [firebase_core_platform_interface firebase_core_web flutter meta]
- firebase_crashlytics 2.2.1 [firebase_core firebase_core_platform_interface firebase_crashlytics_platform_interface flutter stack_trace]
- firebase_database 8.0.0 [firebase_core firebase_database_platform_interface firebase_database_web flutter]
- flutter 0.0.0 [characters collection meta typed_data vector_math sky_engine]
- fluttertoast 8.0.8 [flutter flutter_web_plugins]
- google_sign_in 5.1.0 [flutter google_sign_in_platform_interface google_sign_in_web meta]
- package_info 2.0.2 [flutter]
- random_string 2.3.1
- shared_preferences 2.0.8 [flutter meta shared_preferences_linux shared_preferences_macos shared_preferences_platform_interface shared_preferences_web shared_preferences_windows]
- url_launcher 6.0.11 [flutter meta url_launcher_linux url_launcher_macos url_launcher_platform_interface url_launcher_web url_launcher_windows]

dev dependencies:
- flutter_lints 1.0.4 [lints]
- flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters charcode collection matcher meta source_span stream_channel string_scanner term_glyph typed_data]

transitive dependencies:
- async 2.8.1 [collection meta]
- boolean_selector 2.1.0 [source_span string_scanner]
- characters 1.1.0
- charcode 1.3.1
- clock 1.1.0
- collection 1.15.0
- fake_async 1.2.0 [clock collection]
- ffi 1.1.2
- file 6.1.2 [meta path]
- firebase 9.0.2 [http http_parser js]
- firebase_analytics_platform_interface 2.0.1 [flutter meta]
- firebase_analytics_web 0.3.0+1 [firebase firebase_analytics_platform_interface flutter flutter_web_plugins meta]
- firebase_auth_platform_interface 6.1.0 [firebase_core flutter meta plugin_platform_interface]
- firebase_auth_web 3.1.0 [firebase_auth_platform_interface firebase_core firebase_core_web flutter flutter_web_plugins http_parser intl js meta]
- firebase_core_platform_interface 4.0.1 [collection flutter meta plugin_platform_interface]
- firebase_core_web 1.1.0 [firebase_core_platform_interface flutter flutter_web_plugins js meta]
- firebase_crashlytics_platform_interface 3.1.2 [collection firebase_core flutter meta plugin_platform_interface]
- firebase_database_platform_interface 0.1.0 [collection firebase_core flutter meta plugin_platform_interface]
- firebase_database_web 0.1.0 [firebase_core firebase_core_web firebase_database_platform_interface flutter flutter_web_plugins js]
- flutter_web_plugins 0.0.0 [flutter js characters collection meta typed_data vector_math]
- google_sign_in_platform_interface 2.0.1 [flutter meta quiver]
- google_sign_in_web 0.10.0+3 [flutter flutter_web_plugins google_sign_in_platform_interface js meta]
- http 0.13.3 [async http_parser meta path pedantic]
- http_parser 4.0.0 [charcode collection source_span string_scanner typed_data]
- intl 0.17.0 [clock path]
- js 0.6.3
- lints 1.0.1
- matcher 0.12.10 [stack_trace]
- meta 1.7.0
- path 1.8.0
- path_provider_linux 2.1.0 [flutter path path_provider_platform_interface xdg_directories]
- path_provider_platform_interface 2.0.1 [flutter meta platform plugin_platform_interface]
- path_provider_windows 2.0.3 [ffi flutter meta path path_provider_platform_interface win32]
- pedantic 1.11.1
- platform 3.0.2
- plugin_platform_interface 2.0.1 [meta]
- process 4.2.3 [file path platform]
- quiver 3.0.1 [matcher]
- shared_preferences_linux 2.0.2 [file meta flutter path path_provider_linux shared_preferences_platform_interface]
- shared_preferences_macos 2.0.2 [flutter shared_preferences_platform_interface]
- shared_preferences_platform_interface 2.0.0 [flutter]
- shared_preferences_web 2.0.2 [flutter flutter_web_plugins meta shared_preferences_platform_interface]
- shared_preferences_windows 2.0.2 [flutter file meta path path_provider_platform_interface path_provider_windows shared_preferences_platform_interface]
- sky_engine 0.0.99
- source_span 1.8.1 [collection path term_glyph]
- stack_trace 1.10.0 [path]
- stream_channel 2.1.0 [async]
- string_scanner 1.1.0 [charcode source_span]
- term_glyph 1.2.0
- test_api 0.4.2 [async boolean_selector collection meta source_span stack_trace stream_channel string_scanner term_glyph matcher]
- typed_data 1.3.0 [collection]
- url_launcher_linux 2.0.2 [flutter]
- url_launcher_macos 2.0.2 [flutter]
- url_launcher_platform_interface 2.0.4 [flutter plugin_platform_interface]
- url_launcher_web 2.0.4 [flutter flutter_web_plugins meta url_launcher_platform_interface]
- url_launcher_windows 2.0.2 [flutter]
- vector_math 2.1.0
- win32 2.2.9 [ffi]
- xdg_directories 0.2.0 [meta path process]

</details>


created time in 2 months

issue commentflutter/flutter

Code Push / Hot Update / out of band updates

Think about it guys, how is it even possible to live update except to use something interpreted alongside the native code in Flutter. You're using an amazing UI framework that generates native code with a completely native UI and you want the ability to hack it up so you can update it over the air. The Google team said it early on in the conversation, doing so would mean a complete overhaul of the framework and, due to losing the compiled native aspect of the apps you build today, nobody will be happy with the results. React Native can do this because it has a JavaScript interpreted layer already today. The Hydro SDK mentioned above hacks a Lua and TypeScript layer on top of flutter but that's an awful lot of work to go through to get this feature.

eseidelGoogle

comment created time in 3 months

more