Animation use one refreshController to multiple SmartRefresher

Viewed 41

I am trying to use the package page_flip_builder to display my notifications in a drawer. The only problem is that animation builds multiple times so the GetX Provider also asks multiple times for his Refresh Controller. The screen works great if I use it outside the page_flip_builder animation. Is there a way to overcome it?

The error I am getting:

Don't use one refreshController to multiple SmartRefresher,It will cause some unexpected bugs mostly in TabBarView

The Drawer:

import 'package:flutter/material.dart';
import 'package:lazy_load_indexed_stack/lazy_load_indexed_stack.dart';
import 'package:page_flip_builder/page_flip_builder.dart';

import '../imports.dart';
import '../modules/chat/pages/chats/chat_list.dart';
import '../modules/chat/pages/groups/groups_list.dart';
import '../modules/notifications/pages/index.dart';
import 'menu_page.dart';

class HomeDrawer extends StatefulWidget {
  @override
  _HomeDrawerState createState() => _HomeDrawerState();
}

class _HomeDrawerState extends State<HomeDrawer> {
  final pageFlipKey = GlobalKey<PageFlipBuilderState>();
  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Drawer(
      child: Container(
        height: context.height,
        color: theme.primaryColorDark,
        child: SafeArea(
          child: Container(
            color: Colors.black,
            child: PageFlipBuilder(
              key: pageFlipKey,
              frontBuilder: (_) => MenuPage(
                onFlip: () => pageFlipKey.currentState?.flip(),
              ),
              backBuilder: (_) => 
                  NotificationScreen(
                    onFlip: () => pageFlipKey.currentState?.flip(),
                  ),
              maxTilt: 0.003,
              maxScale: 0.2,
              onFlipComplete: (isFrontSide) => print('front: $isFrontSide'),
            ),
          ),
        ),
      ),
    );
  }
}

Menu page:

import 'package:flutter/material.dart';

import '../imports.dart';

class MenuPage extends StatelessWidget {
  final VoidCallback? onFlip;
  const MenuPage({Key? key, this.onFlip}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final whiteColor = Colors.white;
    return Drawer(
      child: Container(
        height: context.height,
        decoration: BoxDecoration(gradient: AppStyles.primaryGradient),
        child: SafeArea(
          child: Column(
            // crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              BottomFlipIconButton(onFlip: onFlip),
              SizedBox(
                // color: Colors.redAccent,
                height: 50,
                child: Align(
                  alignment: Alignment.bottomRight,
                  child: IconButton(
                    padding: EdgeInsets.only(right: 15),
                    constraints: BoxConstraints(),
                    onPressed: () => Get.back(),
                    icon: Icon(
                      menuIcons['exit'],
                      color: whiteColor,
                    ),
                  ),
                ),
              ),
              MenuTile(
                title: menuStrings['notifications']!,
                icon: menuIcons['notifications'],
                onTap: () {
                  onFlip?.call();
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

final Map<String, IconData> menuIcons = {
  'notifications': Icons.notifications,

};
final Map<String, String> menuStrings = {
  'notifications': 'Notifications',
};

class MenuTile extends StatelessWidget {
  final IconData? icon;
  final double? iconSize;
  final String? title;
  final bool isPadding;
  final void Function()? onTap;

  const MenuTile(
      {Key? key,
      this.icon,
      this.title,
      this.onTap,
      this.iconSize,
      this.isPadding = true})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListTile(
      dense: true,
      tileColor: Colors.redAccent,
      horizontalTitleGap: 8,
      contentPadding:
          EdgeInsets.symmetric(horizontal: 36, vertical: isPadding ? 8 : 0),
      leading: Icon(
        icon,
        color: Colors.white.withOpacity(0.5),
        size: iconSize,
      ),
      title: Text(
        title == null ? '' : title!.toUpperCase(),
        style: TextStyle(
          fontSize: 15,
          fontWeight: FontWeight.bold,
          color: AppStyles.whiteMenuColor,
          letterSpacing: 3,
        ),
      ),

      onTap: onTap,
    );
  }
}

class BottomFlipIconButton extends StatelessWidget {
  const BottomFlipIconButton({Key? key, this.onFlip}) : super(key: key);
  final VoidCallback? onFlip;
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        IconButton(
          onPressed: onFlip,
          icon: const Icon(Icons.flip),
        )
      ],
    );
  }
}

Notification Screen:

import 'package:flutter/material.dart';

import 'package:google_fonts/google_fonts.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';

import '../../../imports.dart';
import '../models/notification.dart';
import '../provider.dart';
import 'widget/item.dart';

class NotificationScreen extends StatelessWidget {
  final VoidCallback? onFlip;

  const NotificationScreen({Key? key, this.onFlip}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    print('building notifications page');
    final theme = Theme.of(context);
    return SafeArea(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          IconButton(
            onPressed: () {
              onFlip?.call();
              // appPrefs.drawerState(DrawerState.Menu);
            },
            icon: Icon(Icons.arrow_back),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.only(top: 4, bottom: 8, left: 20),
                child: Text(
                  t.Notifications,
                  style: GoogleFonts.basic(
                    textStyle: theme.textTheme.headline5,
                  ),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Icon(
                  Icons.notifications,
                ),
              ),
            ],
          ),
          Expanded(
            child: Obx(
              () => StreamBuilder<List<NotificationModel>>(
                stream: notificationProvider.notsStream,
                builder: (_, snapshot) {
                  final nots = snapshot.data ?? [];
                  return SmartRefresher(
                    controller: notificationProvider.refreshController,
                    enablePullDown: false,
                    enablePullUp: notificationProvider.limit() <= nots.length,
                    onLoading: notificationProvider.onLoadMore,
                    child: ListView.builder(
                      itemCount: nots.length,
                      itemBuilder: (_, i) => NotificationItem(nots[i]),
                    ),
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Notification Provider:

import 'dart:async';

import 'package:pull_to_refresh/pull_to_refresh.dart';

import '../../imports.dart';
import 'data/notifications.dart';
import 'models/notification.dart';

NotificationProvider get notificationProvider =>
    Get.find<NotificationProvider>();

class NotificationProvider {
  RefreshController refreshController = RefreshController();

  StreamSubscription<List<NotificationModel>>? notListener;
  void init() {
    refreshController = RefreshController();
    notListener = NotificationRepo.notsStream(2)
        .listen(NotificationRepo.checkIfToShowNotification);
  }

  final limit = 20.obs;
  Stream<List<NotificationModel>> get notsStream =>
      NotificationRepo.notsStream(limit());

  void onLoadMore() {
    limit.value += 20;
    refreshController.loadComplete();
  }

  Future<void> dispose() async {
    refreshController.dispose();
    await notListener?.cancel();
    notListener = null;
  }
}
0 Answers
Related