Skip to content

Duplicate Code: Identical EmptyCard and InitialCard Widgets #39

@github-actions

Description

@github-actions

Summary

The EmptyCard and InitialCard widgets are functionally identical - both render empty centered columns with the same implementation. This is a 100% code duplication that should be consolidated into a single reusable component.

Duplication Details

Pattern: Identical Widget Implementations

  • Severity: High
  • Occurrences: 2 instances
  • Locations:
    • lib/ui/widgets/empty_card.dart:3-17
    • lib/ui/widgets/initial_card.dart:3-17

Code Sample:

// empty_card.dart
class EmptyCard extends StatelessWidget {
  const EmptyCard({
    Key? key,
  }) : super(key: key);

  `@override`
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: const [],
      ),
    );
  }
}

// initial_card.dart - IDENTICAL except class name
class InitialCard extends StatelessWidget {
  const InitialCard({
    Key? key,
  }) : super(key: key);

  `@override`
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: const [],
      ),
    );
  }
}

Impact Analysis

  • Maintainability: Any changes to the empty state UI must be duplicated across both files, increasing the risk of inconsistencies
  • Bug Risk: If one widget is updated but not the other, the app will have inconsistent empty state behavior
  • Code Bloat: 17 lines of unnecessary duplicate code

Refactoring Recommendations

Option 1: Single Widget with Type Parameter (Recommended)

Extract to a single PlaceholderCard widget with a parameter to distinguish between states:

class PlaceholderCard extends StatelessWidget {
  final PlaceholderType type;
  
  const PlaceholderCard({
    Key? key,
    this.type = PlaceholderType.empty,
  }) : super(key: key);

  `@override`
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: const [],
      ),
    );
  }
}

enum PlaceholderType { empty, initial }

Option 2: Named Constructors

Use a single widget with named constructors:

class PlaceholderCard extends StatelessWidget {
  const PlaceholderCard({Key? key}) : super(key: key);
  
  const PlaceholderCard.empty({Key? key}) : super(key: key);
  const PlaceholderCard.initial({Key? key}) : super(key: key);

  `@override`
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: const [],
      ),
    );
  }
}

Option 3: Type Aliases

If the widgets truly need to remain separate for semantic reasons, use type aliases:

typedef EmptyCard = PlaceholderCard;
typedef InitialCard = PlaceholderCard;

Implementation Checklist

  • Review current usage of EmptyCard and InitialCard to determine if they need different behavior
  • Choose refactoring approach (Option 1 recommended)
  • Create unified PlaceholderCard widget
  • Update all references to EmptyCard and InitialCard
  • Remove duplicate widget files
  • Update widget exports in lib/ui/widgets/widgets.dart
  • Run tests to verify no functionality broken

Analysis Metadata

  • Analyzed Files: 25 Dart files
  • Detection Method: Semantic code analysis
  • Commit: eaf30ea
  • Analysis Date: 2026-02-18
  • Duplication Size: 17 lines (100% match)

AI generated by Duplicate Code Detector

To add this workflow in your repository, run gh aw add github/gh-aw/.github/workflows/duplicate-code-detector.md@94662b1dee8ce96c876ba9f33b3ab8be32de82a4. See usage guide.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions