pomoworko.com
pomoworko.com

Reputation: 1118

Integrating Timer Control from StartPomodoro Widget into GNav Widget in Flutter

I'm developing a timer application in Flutter and I've encountered an issue with restructuring my UI. Specifically, I need to move the start/pause button from the StartPomodoro widget to a GNav widget in my HomePageTimerUI while maintaining the timer's functionality and controlling animations.

Here's the layout I currently have:

enter image description here

And here's what I'm aiming to achieve:

enter image description here

The challenge arises because my StartPomodoro page contains all the logic for controlling the timer and animations. When I try to cut and paste the start widget into the HomePageTimerUI, I can't seem to integrate it properly.

Here are the relevant parts of my code:

HomePageTimerUI.dart

class HomePageTimerUI extends StatefulWidget {
  const HomePageTimerUI({Key? key}) : super(key: key);

  @override
  State<HomePageTimerUI> createState() => _HomePageTimerUIState();
}

class _HomePageTimerUIState extends State<HomePageTimerUI>
    with TickerProviderStateMixin {
  late TabController _tabController;

  late Timer timer;
  late AnimationController controller;

  String get countText {
    Duration count = controller.duration! * controller.value;
    return controller.isDismissed
        ? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
        : '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
  }

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

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

  void notify() {
    if (countText == '00:00:00') {
      _tabController.animateTo(1, duration: const Duration(milliseconds: 300));
    }
  }

  @override
  
  Widget build(BuildContext context) {
    return Container(
        height: 600,
        width: double.infinity,
        child: DefaultTabController(
            length: 3,
            child: Scaffold(
              appBar: AppBar(
                elevation: 0,
                backgroundColor: Colors.transparent,
                bottom: PreferredSize(
                  preferredSize: Size.fromHeight(55),
                  child: Container(
                    color: Colors.transparent,
                    child: SafeArea(
                      child: Column(
                        children: <Widget>[
                          TabBar(
                              controller: _tabController,
                              indicator: UnderlineTabIndicator(
                                  borderSide: BorderSide(
                                      color: Color(0xff3B3B3B), width: 4.0),
                                  insets: EdgeInsets.fromLTRB(
                                      12.0, 12.0, 12.0, 11.0)),
                              indicatorWeight: 15,
                              indicatorSize: TabBarIndicatorSize.label,
                              labelColor: Color(0xff3B3B3B),
                              labelStyle: TextStyle(
                                  fontSize: 12,
                                  letterSpacing: 1.3,
                                  fontWeight: FontWeight.w500),
                              unselectedLabelColor: Color(0xffD7D7D7),
                              tabs: [
                                Tab(
                                  text: "POMODORO",
                                  icon: Icon(Icons.work_history, size: 40),
                                ),
                                Tab(
                                  text: "SHORT BREAK",
                                  icon: Icon(Icons.ramen_dining, size: 40),
                                ),
                                Tab(
                                  text: "LONG BREAK",
                                  icon: Icon(
                                      Icons.battery_charging_full_rounded,
                                      size: 40),
                                ),
                              ])
                        ],
                      ),
                    ),
                  ),
                ),
              ),
              body: TabBarView(
                controller: _tabController,
                children: <Widget>[
                  Center(
                    child: StartPomodoro(),
                  ),
                  // Center(
                  //   child: ShortBreak(),
                  // ),
                  // Center(child: LongBreak()),
                ],
              ),
              bottomNavigationBar: Container(
                height: 110,
                color: Color(0xffFAFAFA),
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                      horizontal: 15.0, vertical: 20),
                  child: GNav(
                    iconSize: 40,
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    backgroundColor: Color(0xffFAFAFA),
                    color: Color(0xffD7D7D7),
                    activeColor: Color(0xff3B3B3B),
                    tabBackgroundColor: Color(0xffF0F0F0),
                    gap: 8,
                    onTabChange: (index) {
                      print(index);
                    },
                    padding: EdgeInsets.all(15),
                    tabs: [
                      GButton(
                        icon: Icons.settings,
                        text: 'Settings',
                      ),
                      GButton(
                        icon: Icons.person,
                        text: "Profile",
                      ),
                      GButton(
                        icon: Icons.task,
                        text: "Tasks",
                      ),
                      GButton(
                        icon: Icons.show_chart,
                        text: "Performance",
                      ),
                    ],
                  ),
                ),
              ),
            )));
  }
}

startpomodoro.dart

class StartPomodoro extends StatefulWidget {
  const StartPomodoro({Key? key}) : super(key: key);

  @override
  State<StartPomodoro> createState() => _StartPomodoroState();
}

class _StartPomodoroState extends State<StartPomodoro>
    with TickerProviderStateMixin {
      
  List<bool> isSelected = [true, false];
  late Timer timer;
  late AnimationController controller;

  String get countText {
    Duration count = controller.duration! * controller.value;
    return controller.isDismissed
        ? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
        : '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
  }

  double progress = 1.0;
  bool LongBreak = true;

  void notify() {
    if (countText == '00:00:00') {}
  }

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 0),
    );
    controller.addListener(() {
      notify();
      if (controller.isAnimating) {
        setState(() {
          progress = controller.value;
        });
      } else {
        setState(() {
          progress = 1.0;
          LongBreak = true;
        });
      }
    });
  }

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

  @override
  
  Widget build(BuildContext context) {
    
    ThemeData themeData = Theme.of(context);
    return Scaffold(
              backgroundColor:
                  LongBreak ? const Color(0xffD94530) : const Color(0xff6351c5),
              body: GestureDetector(
                onTap: () {
                  if (controller.isDismissed) {
                    showModalBottomSheet(
                      context: context,
                      builder: (context) => Container(
                        height: 300,
                        child: CupertinoTimerPicker(
                          initialTimerDuration: controller.duration!,
                          onTimerDurationChanged: (time) {
                            setState(() {
                              controller.duration = time;
                            });
                          },
                        ),
                      ),
                    );
                  }
                },
                child: AnimatedBuilder(
                    animation: controller,
                    builder: (context, child) {
                      return Stack(
                        children: <Widget>[
                          Align(
                            alignment: Alignment.bottomCenter,
                            child: Container(
                              color: const Color(0xffD94530),
                              height: controller.value *
                                  MediaQuery.of(context).size.height *
                                  0.640,
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              children: <Widget>[
                                Expanded(
                                  child: Align(
                                    alignment: Alignment.bottomCenter,
                                    child: Align(
                                      alignment: FractionalOffset.bottomCenter,
                                      child: SingleChildScrollView(
                                        child: Column(
                                          mainAxisAlignment:
                                              MainAxisAlignment.end,
                                          crossAxisAlignment:
                                              CrossAxisAlignment.center,
                                          children: <Widget>[
                                            Text(
                                              countText,
                                              style: const TextStyle(
                                                fontSize: 90.0,
                                                color: Color(0xffFAFAFA),
                                              ),
                                            ),
                                          ],
                                        ),
                                      ),
                                    ),
                                  ),
                                ),
                                Expanded(
                                  child: Column(
                                  
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    crossAxisAlignment:
                                        CrossAxisAlignment.stretch,
                                    children: [
                                      AnimatedBuilder(
                                          animation: controller,
                                          builder: (context, child) {
                                            return const Padding(
                                              padding: EdgeInsets.symmetric(
                                                  vertical: 2.0,
                                                  horizontal: 15.0),
                                            );
                                          }),
                                      AnimatedBuilder(
                                          animation: controller,
                                          builder: (context, child) {
                                            return Padding(
                                              padding: const EdgeInsets.symmetric(
                                                  vertical: 2.0,
                                                  horizontal: 15.0),
                                              child:
                                                  FloatingActionButton.extended(
                                                      backgroundColor:
                                                          const Color(0xffFAFAFA),
                                                      onPressed: () {
                                                        if (controller
                                                            .isAnimating) {
                                                          controller.stop();
                                                          setState(() {
                                                            LongBreak = false;
                                                          });
                                                        } else {
                                                          controller.reverse(
                                                              from: controller
                                                                          .value ==
                                                                      0
                                                                  ? 1.0
                                                                  : controller
                                                                      .value);
                                                          setState(() {
                                                            LongBreak = false;
                                                          });
                                                        }
                                                      },
                                                      icon: Icon(
                                                        controller.isAnimating
                                                            ? Icons.pause
                                                            : Icons.play_arrow,
                                                        color:
                                                            const Color(0xff3B3B3B),
                                                      ),
                                                      label: Text(
                                                        controller.isAnimating
                                                            ? "Pause"
                                                            : "Start",
                                                        style: const TextStyle(
                                                            color: Color(
                                                                0xff3B3B3B)),
                                                      )),
                                            );
                                          }),
                                      const SizedBox(width: 20, height: 100),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ],
                      );
                    }),
              ),
            );}
 
}

How can I replace the start/pause button into the GNav widget while maintaining its height and also initialize the timer correctly in this new structure?

Thank you for any assistance you can provide.

Upvotes: 0

Views: 170

Answers (1)

krishnaacharyaa
krishnaacharyaa

Reputation: 24980

It's difficult to precisely figure out from the code produced. Because of too many widgets and wrong indentations. I would give suggestions based on rough insights.

If you want to seperate two elements use Spacer that will do the job for you, Otherwise try the following approach.

Present approach (roughly)

Column
 |_ Timer Container
 |_ Floating button

to

Correct appraoch

Column
 |_ Expanded
   |_ Center
     |_ Timer Container
 |_ Floating Button

Upvotes: 1

Related Questions