Skip to content

Refactor: Creating a separate widget for "Save/Update" floating action button in the add_or_update_alarm_view.dart #654

@amaydixit11

Description

@amaydixit11
Contributor

Description

Problem

  • A few files (like add_or_update_alarm_view.dart) have grown to over 1000 lines of code
  • As discussed with @MarkisDev, this needs modularization for better code organization
  • The floating action button implementation contains business logic mixed with UI code
  • This leads to
    • Reduced code maintainability
    • Harder to test individual components
    • Difficult to reuse components
    • Increased cognitive load for developers
  • The large file size and mixed concerns make the code harder to maintain and understand

Proposed Solution

  1. Extract the floating action button into a separate widget component
  2. Implement proper separation of concerns
  3. Create a clean, reusable Floating Action Button widget

Benefits of This Refactoring

  1. Separation of Concerns

    • UI logic is separated from business logic
    • Button appearance and behavior are encapsulated
    • Permissions checking is handled cleanly
  2. Improved Maintainability

    • Smaller, focused components
    • Clear responsibilities for each class
    • Easier to test individual components
  3. Better Reusability

    • Floating Action Button widget can be reused across the app
    • Consistent styling and behavior
    • Configurable through parameters
  4. Code Organization

    • Reduced file size in main view
    • Better folder structure
    • Clearer component boundaries

Here's the implementation:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:ultimate_alarm_clock/app/utils/constants.dart';
import 'package:ultimate_alarm_clock/app/utils/utils.dart';
import '../controllers/add_or_update_alarm_controller.dart';
import 'package:ultimate_alarm_clock/app/modules/settings/controllers/theme_controller.dart';

class SaveOrUpdateFloatingActionButton extends GetView<AddOrUpdateAlarmController> {
  const SaveOrUpdateFloatingActionButton({
    Key? key,
    required this.onSavePressed,
  }) : super(key: key);

  final Future<void> Function() onSavePressed;

  @override
  Widget build(BuildContext context) {
    final themeController = Get.find<ThemeController>();
    final width = MediaQuery.of(context).size.width;
    final height = MediaQuery.of(context).size.height;

    return Obx(
      () => controller.mutexLock.value
          ? const SizedBox()
          : Padding(
              padding: const EdgeInsets.all(18.0),
              child: SizedBox(
                height: height * 0.06,
                width: width * 0.8,
                child: TextButton(
                  style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all(kprimaryColor),
                  ),
                  onPressed: () async {
                    Utils.hapticFeedback();
                    await _handleButtonPress();
                  },
                  child: Text(
                    _getButtonText(),
                    style: Theme.of(context).textTheme.displaySmall!.copyWith(
                          color: themeController.secondaryTextColor.value,
                        ),
                  ),
                ),
              ),
            ),
    );
  }

  String _getButtonText() {
    return controller.alarmRecord.value.alarmID.isEmpty 
        ? 'Save'.tr 
        : 'Update'.tr;
  }

  Future<void> _handleButtonPress() async {
    await controller.checkOverlayPermissionAndNavigate();

    if (!await _checkRequiredPermissions()) return;

    await onSavePressed();
  }

  Future<bool> _checkRequiredPermissions() async {
    return await Permission.systemAlertWindow.isGranted &&
        await Permission.ignoreBatteryOptimizations.isGranted;
  }
}

Usage in Original File

Replace the existing Floating Action Button code in add_or_update_alarm_view.dart with:

floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: SaveOrUpdateFloatingActionButton(
  onSavePressed: () async {
    if (!controller.homeController.isProfile.value) {
      await _handleAlarmSave();
    } else if (controller.profileTextEditingController.text.isNotEmpty) {
      controller.createProfile();
    }
  },
),

Screenshots

No response

Activity

amaydixit11

amaydixit11 commented on Jan 29, 2025

@amaydixit11
ContributorAuthor

@MarkisDev Can i be assigned to this issue?

MarkisDev

MarkisDev commented on Jan 29, 2025

@MarkisDev
Member

@amaydixit11 I have assigned this to you. The button is no longer a floating action button with the latest merge. Please do separate out the business logic from UI for now.

Additionally, you can look into modularising some pieces of code (ex the button, popups etc) so we can centralize it's implementation throughout the application.

amaydixit11

amaydixit11 commented on Jan 29, 2025

@amaydixit11
ContributorAuthor

I've raised a PR for this, can you please review it @MarkisDev

amaydixit11

amaydixit11 commented on Jan 29, 2025

@amaydixit11
ContributorAuthor

Additionally, I plan to raise another issue soon, to further refactor the add_or_update_alarm_view.dart, for example making the list view reusable by efficiently handling the list of options shown, and modularizing the Time setting number picker for the alarms,
I'll do the above once this PR is merged to avoid merge conflicts

Gaurav-Kushwaha-1225

Gaurav-Kushwaha-1225 commented on Apr 12, 2025

@Gaurav-Kushwaha-1225
Contributor

Hi @MarkisDev,
I've opened PR #814 to address the refactoring issue, as PR #670 has been inactive for over a month.
Kindly take a moment to review it when possible. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Refactor: Creating a separate widget for "Save/Update" floating action button in the add_or_update_alarm_view.dart · Issue #654 · CCExtractor/ultimate_alarm_clock