Skip to content

Slow scrolling when lazy loading elements #55922

@marinatrajk

Description

@marinatrajk
class TemplatesView extends StatefulWidget {
  const TemplatesView({
    Key key,
  }) : super(key: key);

  @override
  _TemplatesViewState createState() => _TemplatesViewState();
}

class _TemplatesViewState extends State<TemplatesView> {
  bool _showMyStories = false;
  @override
  void initState() {
    super.initState();
  }

  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomPadding: false,
      appBar: AppBar(
        elevation: 0.0,
        backgroundColor: ThemeData.dark().scaffoldBackgroundColor,
        automaticallyImplyLeading: false,
        title: Text(
          _showMyStories ? 'My Stories' : I18n.of(context).templatesTitle,
          style: TextStyle(
            fontWeight: FontWeight.w100,
            fontSize: 16,
          ),
        ),
        actions: <Widget>[
          IconButton(
            tooltip: 'My Stories',
            icon: Icon(_showMyStories ? Icons.grid_on : Icons.person),
            onPressed: () {
              if (mounted)
                setState(() {
                  _showMyStories = !_showMyStories;
                });
            },
          ),
        ],
      ),
      body: Container(
        color: ThemeData.dark().scaffoldBackgroundColor,
        padding: EdgeInsets.only(left: 10, right: 10),
        child: IndexedStack(
          index: _showMyStories ? 1 : 0,
          children: <Widget>[
            _buildStoriesList(
              context,
              Provider.of<TemplatesModel>(context, listen: false).templates,
            ),
            _buildStoriesList(
              context,
              Provider.of<StoriesModel>(context, listen: false).stories,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildStoriesList(
      BuildContext context, ValueNotifier<List<AmpStory>> listen) {
    return LayoutBuilder(
      builder: (context, dimens) => ValueListenableBuilder<List<AmpStory>>(
          valueListenable: listen,
          builder: (context, stories, child) {
            if (stories == null) {
              return Container(
                child: Center(
                  child: CircularProgressIndicator(),
                ),
              );
            }
            if (stories.isEmpty) {
              return Container(
                child: Center(
                  child: Text(
                    'No Templates',
                    style:
                        TextStyle(color: ThemeData.dark().textSelectionColor),
                  ),
                ),
              );
            }
            return Scrollbar(
              child: GridView.builder(
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: (dimens.maxWidth / 175).ceil(),
                    childAspectRatio: 9 / 16),
                itemCount: stories.length,
                itemBuilder: (context, index) {
                  final story = stories[index];
                  return PremiumTemplatePreview(story: story);
                },
              ),
            );
          }),
    );
  }
}

class PremiumTemplatePreview extends StatefulWidget {
  final AmpStory story;

  const PremiumTemplatePreview({
    Key key,
    @required this.story,
  }) : super(key: key);

  @override
  _PremiumTemplatePreviewState createState() => _PremiumTemplatePreviewState();
}

class _PremiumTemplatePreviewState extends State<PremiumTemplatePreview>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation<double> animation;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 100),
    )..addListener(() => setState(() {}));
    animation = Tween<double>(begin: 0.9, end: 1).animate(animationController);
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onEnter: (_) {
        animationController.forward();
      },
      onExit: (_) {
        animationController.reverse();
      },
      child: Container(
        constraints: BoxConstraints.expand(
          height: 200.0,
        ),
        child: AnimatedBuilder(
          animation: animation,
          builder: (context, child) => Container(
              padding: EdgeInsets.all(2),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(5),
              ),
              child: Transform.scale(
                scale: animation.value,
                child: InkWell(
                  child: Stack(
                    children: <Widget>[
                      Positioned.fill(
                        child: Image.network(
                          widget.story?.image != null &&
                                  widget.story.image.isNotEmpty
                              ? widget.story.image
                              : 'https://firebasestorage.googleapis.com/v0/b/ampstor.appspot.com/o/images%2FAmpstor_Android_story.png?alt=media&token=1d08b404-64e7-4bb9-94c0-9c74121bfcc9',
                          fit: BoxFit.cover,
                        ),
                      ),
                      Positioned(
                        right: 5.0,
                        top: 5.0,
                        child: Text(
                          'FREE',
                          style: TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                            fontSize: 9,
                          ),
                        ),
                      ),
                      Positioned(
                        right: 5.0,
                        bottom: 5.0,
                        child: Text(
                          widget.story.name,
                          style: TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                            fontSize: 9,
                          ),
                        ),
                      ),
                    ],
                  ),
                  onTap: () async {
                    final _story = widget.story;
                    final value = await showDialog<bool>(
                        context: context,
                        builder: (context) => Center(
                              child: Material(
                                elevation: 10,
                                color: Colors.transparent,
                                child: Column(
                                  mainAxisSize: MainAxisSize.min,
                                  children: <Widget>[
                                    SizedBox(
                                      width: defaultDevice.width,
                                      height: defaultDevice.height,
                                      child: AspectRatio(
                                        aspectRatio: 1,
                                        child: MobileView(
                                          story: _story,
                                          showDownloadImage: false,
                                        ),
                                      ),
                                    ),
                                    RaisedButton(
                                      child: Text(
                                        'Select this template',
                                        style: TextStyle(
                                            color: UIColors.greyishBrown),
                                      ),
                                      onPressed: () {
                                        Navigator.maybePop(context, true);
                                      },
                                    )
                                  ],
                                ),
                              ),
                            ));
                    if (value != null && value)
                      showDialog(
                        context: context,
                        builder: (BuildContext context) {
                          return AlertDialog(
                            title: Text(
                              'You are about to apply new template and lose all content!',
                              style: TextStyle(fontSize: 14),
                            ),
                            content: Text(
                              "Are you sure want to proceed ?",
                              style: TextStyle(fontSize: 12),
                            ),
                            actions: <Widget>[
                              InkWell(
                                  child: Container(
                                      padding: EdgeInsets.symmetric(
                                          vertical: 8.0, horizontal: 20),
                                      child: Text("YES")),
                                  onTap: () {
                                    Provider.of<StoryModel>(context,
                                            listen: false)
                                        .overrideStory(widget.story, true);

                                    Navigator.of(context).pop();
                                    final _model = Provider.of<StoryModel>(
                                        context,
                                        listen: false);
                                    _model.updateTemplateCount();
                                  }),

                              FlatButton(
                                child: Text("NO"),
                                onPressed: () {
                                  //Put your code here which you want to execute on No button click.
                                  Navigator.of(context).pop();
                                },
                              ),

//            FlatButton(
//              child: Text("CANCEL"),
//              onPressed: () {
//                //Put your code here which you want to execute on Cancel button click.
//                Navigator.of(context).pop();
//              },
//            ),
                            ],
                          );
                        },
                      );
                  },
                ),
              )),
        ),
      ),
    );
  }
}

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel master, 1.18.0-9.0.pre.45, on Mac OS X 10.15.4 19E287, locale en-US)

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[!] Xcode - develop for iOS and macOS (Xcode 11.4.1)
! CocoaPods 1.7.5 out of date (1.8.0 is recommended).
CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
Without CocoaPods, plugins will not work on iOS or macOS.
For more info, see https://flutter.dev/platform-plugins
To upgrade:
sudo gem install cocoapods
[✓] Chrome - develop for the web
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.44.2)
[✓] Connected device (3 available)

! Doctor found issues in 1 category.

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work listcustomer: web10platform-webWeb applications specifically

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions