Quantcast
Channel: Active questions tagged consumer - Stack Overflow
Viewing all articles
Browse latest Browse all 87

Flutter Dialog unintentionaly triggers recreating of layout behind

$
0
0

I have an issue with my FLutter code that I am not able to solve neither to understand why this is happening.

First the code in questoin:

import 'dart:io';import 'dart:ui';import 'package:app/controller/api/api.dart';import 'package:app/data/holder/sidebar_entries_holder.dart';import 'package:app/data/holder/date_holder.dart';import 'package:app/data/holder/user_holder.dart';import 'package:app/data/models/user.dart';import 'package:app/exceptions/login/not_logged_in_exception.dart';import 'package:app/ui/views/login/login_view.dart';import 'package:app/ui/views/responsive/home/mobile/home_mobile_view.dart';import 'package:app/ui/views/responsive/responsive_view.dart';import 'package:app/utils/common/common_functions.dart';import 'package:app/utils/log/log.dart';import 'package:flutter/material.dart';import 'package:flutter/services.dart';import 'package:provider/provider.dart';import 'package:responsive_builder/responsive_builder.dart';void main() async {  WidgetsFlutterBinding.ensureInitialized();  await Log.initialize();  HttpOverrides.global = MyHttpOverrides();  final userHolder = UserHolder();  final dateHOlder = DateHolder();  final sideBarEntriesHolder = SideBarEntriesHolder();  final selectedSideBarEntryHolder = SelectedSideBarEntryHolder();  final window = PlatformDispatcher.instance.views.first;  final screenWidth = window.physicalSize.width / window.devicePixelRatio;  final screenHeight = window.physicalSize.height / window.devicePixelRatio;  final isHandy = screenWidth < 600;  if (isHandy) {    SystemChrome.setPreferredOrientations([      DeviceOrientation.portraitUp,      DeviceOrientation.portraitDown,    ]);  } else {    SystemChrome.setPreferredOrientations([      DeviceOrientation.landscapeLeft,      DeviceOrientation.landscapeRight,    ]);  }  try {    final User user = await Api.getUserFromLocalDatabase();    userHolder.setUser(user);    Api.setUserHolder(userHolder);  } catch (e) {    if (e is NotLoggedInException) {      Log.warning("No user currently logged in. Will be forwarded to the login view");    } else {      Log.severe("Error $e will be forwarded to the login view");    }  }  runApp(    MultiProvider(      providers: [        ChangeNotifierProvider.value(value: userHolder),        ChangeNotifierProvider.value(value: dateHolder),        ChangeNotifierProvider.value(value: sideBarEntriesHolder),        ChangeNotifierProvider.value(value: selectedSideBarEntryHolder),      ],      child: const MaterialApp(        debugShowCheckedModeBanner: false,        home: MyApp(),      ),    ),  );}class MyApp extends StatefulWidget {  const MyApp({Key? key}) : super(key: key);  @override  _MyAppState createState() => _MyAppState();}class _MyAppState extends State<MyApp> {  @override  Widget build(BuildContext context) {    return const BaseLayout();  }}class BaseLayout extends StatefulWidget {  const BaseLayout({Key? key}) : super(key: key);  @override  _BaseLayoutState createState() => _BaseLayoutState();}class _BaseLayoutState extends State<BaseLayout> {  late SelectedSideBarEntryHolder selectedSideBarEntryHolder;  late UserHolder userHolder;  @override  void initState() {    super.initState();    selectedSideBarEntryHolder = context.read<SelectedSideBarEntryHolder>();    userHolder = context.read<UserHolder>();  }  @override  Widget build(BuildContext context) {    print("ME TOO");    final user = userHolder.user;    if (user != null && user.isAccessTokenValidForRestOfTheDay()) {      return Scaffold(        body: ResponsiveBuilder(builder: (context, sizingInformation) {          if (sizingInformation.isMobile) {            return const HomeMobileView();          } else if (sizingInformation.isTablet) {            return const ResponsiveView();          } else {            return Container();          }        }),        floatingActionButton: Consumer<SelectedSideBarEntryHolder>(          builder: (context, selectedSideBarEntryHolder, child) {            return Visibility(              visible: selectedSideBarEntryHolder.isNotSelected(),              child: FloatingActionButton(                onPressed: () {                  CommonFunctions.showNewDialog(context);                },                child: const Icon(Icons.add),              ),            );          },        ),      );    } else {      return const LoginView();    }  }}import 'package:app/data/holder/sidebar_entries_holder.dart';import 'package:app/data/holder/selected_side_bar_entry_holder.dart';import 'package:app/data/holder/user_holder.dart';import 'package:app/ui/components/appBar/app_bar.dart';import 'package:app/ui/components/dateSelector/date_selector.dart';import 'package:app/ui/components/sidebar/sidebar.dart';import 'package:app/ui/views/responsive/mobile/edit_view.dart';import 'package:app/ui/views/responsive/mobile/info_view.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';import 'package:responsive_builder/responsive_builder.dart';class HomeMobileView extends StatefulWidget {  const HomeMobileView({super.key});  @override  _HomeMobileView createState() => _HomeMobileView();}class _HomeMobileView extends State<HomeMobileView> {  late UserHolder userHolder;  late SideBarEntriesHolder sideBarEntriesHolder;  @override  void initState() {    super.initState();    userHolder = context.read<UserHolder>();    sideBarEntriesHolder = context.read<SideBarEntriesHolder>();  }  double _calculateSidebarWidth(      BuildContext context, DeviceScreenType deviceScreenType) {    var screenWidth = MediaQuery.of(context).size.width;    if (deviceScreenType == DeviceScreenType.mobile) {      return screenWidth;    } else if (deviceScreenType == DeviceScreenType.tablet) {      return screenWidth * 0.3;    } else {      return 300;    }  }  @override  Widget build(BuildContext context) {    return ResponsiveBuilder(      builder: (context, sizingInformation) {        return Consumer<SelectedSideBarEntryHolder>(          builder: (context, selectedSideBarEntryHolder, child) {            if (selectedSideBarEntryHolder.isNotSelected()) {              return Scaffold(                appBar: const AppBar(),                body: Column(                  children: [                    const DateSelector(),                    Expanded(                      child: Sidebar(                        sidebarWidth: _calculateSidebarWidth(                            context, sizingInformation.deviceScreenType),                      ),                    ),                  ],                ),              );            } else {              if (selectedSideBarEntryHolder.isInEditMode()) {                return const EditView();              } else {                return const Scaffold(                  body: InfoView(),                );              }            }          },        );      },    );  }}import 'dart:async';import 'package:app/data/holder/date_holder.dart';import 'package:app/data/holder/selected_side_bar_holder.dart';import 'package:app/ui/modals/error_dialog.dart';import 'package:app/ui/modals/warning_dialog.dart';import 'package:app/utils/log/log.dart';import 'package:app/utils/utils.dart';import 'package:flutter/material.dart';import 'package:app/controller/api/api.dart';import 'package:app/data/holder/sidebar_entries_holder.dart';import 'package:app/data/holder/user_holder.dart';import 'package:app/data/models/Entry.dart';import 'package:app/ui/components/sidebar/sidebar_entry.dart';import 'package:intl/intl.dart';import 'package:provider/provider.dart';class Sidebar extends StatefulWidget {  final double sidebarWidth;  const Sidebar({    Key? key,    required this.sidebarWidth,  }) : super(key: key);  @override  _SidebarState createState() => _SidebarState();}class _SidebarState extends State<Sidebar> {  late UserHolder userHolder;  late DateHolder dateHolder;  late SideBarEntriesHolder sideBarEntriesHolder;  late SelectedSideBarEntryHolder selectedSideBarEntryHolder;  DateTime? lastUpdate;  @override  void initState() {    super.initState();    userHolder = context.read<UserHolder>();    dateHolder = context.read<DateHolder>();    sideBarEntriesHolder = context.read<SideBarEntriesHolder>();    selectedSideBarEntryHolder = context.read<SelectedSideBarEntryHolder>();    _reloadEntries();  }  Future<List<Entry>> _fetchEntries() async {    DateHolder dateHolder = Provider.of<DateHolder>(context, listen: false);    String formattedDate =        DateFormat('yyyy-MM-dd').format(dateHolder.currentDate);    List<Entry> entries = [];    try {      entries = await Api.getEntriesFromRestEndpoint(        formattedDate,        formattedDate,      );      final String formattedCurrentDate =          Utils.formatDate(dateHolder.currentDate);      sideBarEntriesHolder.setEntries(          formattedCurrentDate, entries);      return sideBarEntriesHolder.getEntries(formattedCurrentDate);    } catch (e) {      Log.severe('Error while fetching entries: $e');      return Future.error(e);    }  }  void _reloadEntries() {    setState(() {      lastUpdate = DateTime.now();    });  }  @override  Widget build(BuildContext context) {    print("I AM CALLED");    return Consumer<DateHolder>(      builder: (context, dateHolder, child) {        var futureEntries = _fetchEntries()();        return RefreshIndicator(          onRefresh: () async {            _reloadEntries();          },          child: FutureBuilder<List<Entry>>(            future: futureEntries,            builder: (context, snapshot) {              if (snapshot.connectionState == ConnectionState.waiting) {                return const Center(child: CircularProgressIndicator());              } else if (snapshot.hasError) {                return _buildListOnError(snapshot);              } else if (snapshot.hasData) {                return _buildList(snapshot.data!);              } else {                return _buildEmptyList();              }            },          ),        );      },    );  }  Widget _buildListOnError(      final AsyncSnapshot<List<Entry>> snapshot) {    String currentDate = Utils.formatDate(dateHolder.currentDate);    bool listNotEmpty =        sideBarEntriesHolder.getEntries(currentDate).isNotEmpty;    if (snapshot.error is Exception && listNotEmpty) {      WidgetsBinding.instance.addPostFrameCallback((_) {        WarningDialog.show(            context,"Fehler beim Laden der Daten","Wollen Sie es erneut versuchen ?","Ja, nochmal versuchen","Nein, mit den vorhandenen Daten weiterarbeiten",            onYesPressed: _reloadEntries);      });      return _buildList(          sideBarEntriesHolder.get(currentDate));    } else {      if (sideBarEntriesHolder.cached.containsKey(currentDate)) {        return _buildList(            sideBarEntriesHolder.cached[currentDate]!);      } else {        return _buildEmptyList();      }    }  }  Widget _buildList(List<Entry> entries) {    return entries.isEmpty        ? _buildEmptyList()        : ListView.builder(            itemCount: entries.length,            itemBuilder: (context, index) {              final entry = entries[index];              return SidebarEntry(                entry: entry,                isSelected: false,                onTap: () async {                    ...                },                onLongPress: () {                  showDeleteDialog(entry);                },              );            },          );  }  void showDeleteDialog(final Entry entry) async {    ...  }  void showDeleteInformationDialog() {    ...  }  Future<bool> deleteSideBarEntry(final Entry entry) async {    ...  }  Widget _buildEmptyList() {    return Center(      child: Column(        mainAxisAlignment: MainAxisAlignment.center,        children: [          const Text('Keine Einträge',            style: TextStyle(fontSize: 16),          ),          ElevatedButton(            onPressed: _reloadEntries, // Neuladen der Daten            child: const Text('Neu laden'),          ),        ],      ),    );  }}import 'package:flutter/material.dart';class CommonFunctions {  static Future<void> showNewDialog(BuildContext context) async {    showDialog(      context: context,      barrierDismissible: false,      builder: (BuildContext context) {        return const AlertDialog(            title: Text("My Dialog"),            content: SingleChildScrollView(              physics: ClampingScrollPhysics(),              child: TextField(),            ));      },    );  }}

My issue is: When I open a dialog with the help of showNewDialog I get a dialog with a TextField. When I focus (or defocus) the textfield the SideBar is rebuilded. Only the Sidebar. Means that I see the output of print("I AM CALLED"); from my SideBar many times but I do not see the output of print("ME TOO"); from my BaseLayout.

I do not understand why my SideBar is rebuilded when focusing a textfield in the dialog. Especially because I am using the Consumer pattern to only rebuild the view when I call the notify method.

Does anyone have an idea why my view keeps rebuilding ?

------------ EDIT ------------The SideBar

enter image description here

The Dialog

enter image description here

When I click in the TextField the focus is set and the KeyBoard is shown which triggers the rebuild (multiple times).

enter image description here

Log output when Opening dialog and seting focus

D/InputMethodManager(15863): showSoftInput() view=io.flutter.embedding.android.FlutterView{d6fdf5d VFE...... .F...... 0,0-1080,2296 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUTI/AssistStructure(15863): Flattened final assist data: 384 bytes, containing 1 windows, 3 viewsD/EGL_emulation(15863): app_time_stats: avg=195.49ms min=2.51ms max=2614.66ms count=14D/InsetsController(15863): show(ime(), fromIme=true)D/EGL_emulation(15863): app_time_stats: avg=483.08ms min=1.31ms max=9613.11ms count=20I/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.461095: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.483933: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.527776: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.557668: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.603329: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.603692: Notifiying listeners that entries list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.604326: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.604595: Notifiying listeners that entries list have changedI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.614896: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.646553: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.689545: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.726604: Get Entries from REST endpointI/flutter (15863): I AM CALLEDI/flutter (15863): [INFO] 2024-04-23 07:49:07.761659: Get Entries from REST endpointI/flutter (15863): [INFO] 2024-04-23 07:49:07.814218: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.814865: Notifiying listeners that entries list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.855985: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.856984: Notifiying listeners that entries list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.869618: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.871666: Notifiying listeners that entries list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.886194: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.886997: Notifiying listeners that entries list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.909218: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.910125: Notifiying listeners that entries list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.939734: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.940123: Notifiying listeners that entrties list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.941196: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.941953: Notifiying listeners that entries list have changedI/flutter (15863): [INFO] 2024-04-23 07:49:07.955544: Start sorting entriesI/flutter (15863): [INFO] 2024-04-23 07:49:07.956654: Notifiying listeners that entries list have changedD/EGL_emulation(15863): app_time_stats: avg=32.01ms min=3.19ms max=282.24ms count=25D/EGL_emulation(15863): app_time_stats: avg=493.36ms min=483.87ms max=500.10ms count=3D/EGL_emulation(15863): app_time_stats: avg=510.94ms min=501.94ms max=519.93ms count=2D/EGL_emulation(15863): app_time_stats: avg=497.79ms min=492.59ms max=500.79ms count=3D/EGL_emulation(15863): app_time_stats: avg=504.19ms min=500.70ms max=507.68ms count=2D/EGL_emulation(15863): app_time_stats: avg=496.64ms min=492.22ms max=501.38ms count=3D/EGL_emulation(15863): app_time_stats: avg=500.09ms min=482.98ms max=515.92ms count=3D/EGL_emulation(15863): app_time_stats: avg=500.91ms min=484.92ms max=516.91ms count=2

Similar behaviour can be observed when defocusing the Dialog.It does not happen if I click on a Button in the Dialog or when I am inputing data into the TextField. Only when focusing/defocusing the TextField.


Viewing all articles
Browse latest Browse all 87

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>