diff --git a/ios/Flutter/ephemeral/flutter_lldb_helper.py b/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 000000000..a88caf99d --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/ios/Flutter/ephemeral/flutter_lldbinit b/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 000000000..e3ba6fbed --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/lib/screens/weight_screen.dart b/lib/screens/weight_screen.dart index 6c91935c5..616d0b936 100644 --- a/lib/screens/weight_screen.dart +++ b/lib/screens/weight_screen.dart @@ -47,9 +47,13 @@ class WeightScreen extends StatelessWidget { ); }, ), - body: SingleChildScrollView( - child: Consumer( - builder: (context, provider, child) => WeightOverview(provider), + body: RefreshIndicator( + onRefresh: () => Provider.of(context, listen: false).fetchAndSetEntries(), + child: SingleChildScrollView( + padding: const EdgeInsets.only(bottom: 80.0), + child: Consumer( + builder: (context, provider, child) => WeightOverview(provider), + ), ), ), ); diff --git a/lib/widgets/weight/weight_overview.dart b/lib/widgets/weight/weight_overview.dart index f6f9050ea..6d1d5081e 100644 --- a/lib/widgets/weight/weight_overview.dart +++ b/lib/widgets/weight/weight_overview.dart @@ -68,66 +68,61 @@ class WeightOverview extends StatelessWidget { ], ), ), - SizedBox( - height: 300, - child: RefreshIndicator( - onRefresh: () => _provider.fetchAndSetEntries(), - child: ListView.builder( - padding: const EdgeInsets.all(10.0), - itemCount: _provider.items.length, - itemBuilder: (context, index) { - final currentEntry = _provider.items[index]; - return Card( - child: ListTile( - title: Text( - '${numberFormat.format(currentEntry.weight)} ${weightUnit(profile.isMetric, context)}', - ), - subtitle: Text( - DateFormat.yMd( - Localizations.localeOf(context).languageCode, - ).add_Hm().format(currentEntry.date), - ), - trailing: PopupMenuButton( - itemBuilder: (BuildContext context) { - return [ - PopupMenuItem( - child: Text(AppLocalizations.of(context).edit), - onTap: () => Navigator.pushNamed( - context, - FormScreen.routeName, - arguments: FormScreenArguments( - AppLocalizations.of(context).edit, - WeightForm(currentEntry), - ), - ), - ), - PopupMenuItem( - child: Text(AppLocalizations.of(context).delete), - onTap: () async { - // Delete entry from DB - await _provider.deleteEntry(currentEntry.id!); - - // and inform the user - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - AppLocalizations.of(context).successfullyDeleted, - textAlign: TextAlign.center, - ), - ), - ); - } - }, + ListView.builder( + padding: const EdgeInsets.all(10.0), + // shrinkWrap tells the list to only take up as much space as it needs + shrinkWrap: true, + // NeverScrollable tells the list to let the outer SingleChildScrollView handle the scrolling + physics: const NeverScrollableScrollPhysics(), + itemCount: _provider.items.length, + itemBuilder: (context, index) { + final currentEntry = _provider.items[index]; + return Card( + child: ListTile( + title: Text( + '${numberFormat.format(currentEntry.weight)} ${weightUnit(profile.isMetric, context)}', + ), + subtitle: Text( + DateFormat.yMd( + Localizations.localeOf(context).languageCode, + ).add_Hm().format(currentEntry.date), + ), + trailing: PopupMenuButton( + itemBuilder: (BuildContext context) { + return [ + PopupMenuItem( + child: Text(AppLocalizations.of(context).edit), + onTap: () => Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).edit, + WeightForm(currentEntry), ), - ]; - }, - ), - ), - ); - }, - ), - ), + ), + ), + PopupMenuItem( + child: Text(AppLocalizations.of(context).delete), + onTap: () async { + await _provider.deleteEntry(currentEntry.id!); + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + AppLocalizations.of(context).successfullyDeleted, + textAlign: TextAlign.center, + ), + ), + ); + } + }, + ), + ]; + }, + ), + ), + ); + }, ), ], );