@@ -116,7 +116,14 @@ class _AppSizeBodyState extends State<AppSizeBody>
116116 testAppSizeFile = await server.requestTestAppSizeFile (testFilePath);
117117 }
118118
119- // TODO(kenz): add error handling if the files are null
119+ final errorMessages = < String > [
120+ if (baseAppSizeFile == null ) 'base app size file: $baseFilePath ' ,
121+ if (testAppSizeFile == null ) 'test app size file: $testFilePath ' ,
122+ ];
123+ if (errorMessages.isNotEmpty) {
124+ _pushErrorMessage ('Failed to load ${errorMessages .join (' and ' )}.' );
125+ }
126+
120127 if (baseAppSizeFile != null ) {
121128 if (testAppSizeFile != null ) {
122129 controller.loadDiffTreeFromJsonFiles (
@@ -306,15 +313,78 @@ class DiffTreeTypeDropdown extends StatelessWidget {
306313 }
307314}
308315
316+ enum ImportInstructionType { analysis, diffOld, diffNew }
317+
318+ class _ImportInstructions extends StatelessWidget {
319+ const _ImportInstructions ({this .type = ImportInstructionType .analysis});
320+
321+ final ImportInstructionType type;
322+
323+ @override
324+ Widget build (BuildContext context) {
325+ final theme = Theme .of (context);
326+
327+ List <InlineSpan > buildInstructionText () {
328+ final article = type == ImportInstructionType .diffNew ? 'a' : 'an' ;
329+ final boldText = type == ImportInstructionType .diffOld
330+ ? 'original (old)'
331+ : type == ImportInstructionType .diffNew
332+ ? 'modified (new)'
333+ : null ;
334+
335+ return [
336+ TextSpan (
337+ text: 'Drag and drop $article ' ,
338+ style: theme.regularTextStyle,
339+ ),
340+ if (boldText != null )
341+ TextSpan (text: boldText, style: theme.boldTextStyle),
342+ TextSpan (
343+ text:
344+ '${boldText != null ? ' ' : '' }AOT snapshot or size analysis file'
345+ ' for debugging, or click "Open file".' ,
346+ style: theme.regularTextStyle,
347+ ),
348+ ];
349+ }
350+
351+ return Column (
352+ mainAxisSize: MainAxisSize .min,
353+ mainAxisAlignment: MainAxisAlignment .center,
354+ children: [
355+ RichText (
356+ textAlign: TextAlign .center,
357+ text: TextSpan (children: buildInstructionText ()),
358+ ),
359+ const SizedBox (height: densePadding),
360+ RichText (
361+ textAlign: TextAlign .center,
362+ text: TextSpan (
363+ children: [
364+ TextSpan (text: 'Read ' , style: theme.regularTextStyle),
365+ LinkTextSpan (
366+ link: const Link (
367+ display: 'documentation' ,
368+ url:
369+ 'https://docs.flutter.dev/tools/devtools/app-size#generating-size-files' ,
370+ ),
371+ context: context,
372+ ),
373+ TextSpan (
374+ text: ' to learn how to generate these files.' ,
375+ style: theme.regularTextStyle,
376+ ),
377+ ],
378+ ),
379+ ),
380+ ],
381+ );
382+ }
383+ }
384+
309385class AnalysisView extends StatefulWidget {
310386 const AnalysisView ({super .key});
311387
312- // TODO(kenz): add links to documentation on how to generate these files, and
313- // mention the import file button once it is hooked up to a file picker.
314- static const importInstructions =
315- 'Drag and drop an AOT snapshot or'
316- ' size analysis file for debugging' ;
317-
318388 @override
319389 State <AnalysisView > createState () => _AnalysisViewState ();
320390}
@@ -382,7 +452,7 @@ class _AnalysisViewState extends State<AnalysisView> with AutoDisposeMixin {
382452 children: [
383453 Flexible (
384454 child: FileImportContainer (
385- instructions : AnalysisView .importInstructions ,
455+ instructionsWidget : const _ImportInstructions () ,
386456 actionText: 'Analyze Size' ,
387457 gaScreen: gac.appSize,
388458 gaSelectionImport: gac.importFileSingle,
@@ -407,15 +477,6 @@ class _AnalysisViewState extends State<AnalysisView> with AutoDisposeMixin {
407477class DiffView extends StatefulWidget {
408478 const DiffView ({super .key});
409479
410- // TODO(kenz): add links to documentation on how to generate these files, and
411- // mention the import file button once it is hooked up to a file picker.
412- static const importOldInstructions =
413- 'Drag and drop an original (old) AOT '
414- 'snapshot or size analysis file for debugging' ;
415- static const importNewInstructions =
416- 'Drag and drop a modified (new) AOT '
417- 'snapshot or size analysis file for debugging' ;
418-
419480 @override
420481 State <DiffView > createState () => _DiffViewState ();
421482}
@@ -490,9 +551,12 @@ class _DiffViewState extends State<DiffView> with AutoDisposeMixin {
490551 child: DualFileImportContainer (
491552 firstFileTitle: 'Old' ,
492553 secondFileTitle: 'New' ,
493- // TODO(kenz): perhaps bold "original" and "modified".
494- firstInstructions: DiffView .importOldInstructions,
495- secondInstructions: DiffView .importNewInstructions,
554+ firstInstructionsWidget: const _ImportInstructions (
555+ type: ImportInstructionType .diffOld,
556+ ),
557+ secondInstructionsWidget: const _ImportInstructions (
558+ type: ImportInstructionType .diffNew,
559+ ),
496560 actionText: 'Analyze Diff' ,
497561 gaScreen: gac.appSize,
498562 gaSelectionImportFirst: gac.importFileDiffFirst,
0 commit comments