Skip to content

Refactor themes #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Refactor themes #3

wants to merge 2 commits into from

Conversation

ashtanko
Copy link
Owner

@ashtanko ashtanko commented Mar 22, 2025

Summary by CodeRabbit

  • New Features

    • Expanded theme options now include refreshed Brown, Yellow, and Orange variations for both light and dark modes.
    • Introduced a new ThemeItem component to enhance theme customization.
  • Bug Fixes

    • Improved dependency injection for repositories, ensuring more reliable data retrieval.
  • Style

    • Updated visual mappings for improved color consistency and a modernized look.

These enhancements enrich the overall visual appeal and customization experience for users without changing any core functionality.

Copy link

coderabbitai bot commented Mar 22, 2025

Walkthrough

The changes refactor dependency injection by removing context-based repository providers in favor of direct retrieval via a dependency injection container. The EmailListRepository is now declared as an abstract class with a concrete implementation, and its registration has been added to the DI initializer. Several theme-related modifications have been made: theme mappings in the theme cubit have been updated, new theme classes (BrownTheme, OrangeTheme, YellowTheme) and supporting color model classes (ColorFamily, ExtendedColor) have been introduced, and the MaterialTheme class now delegates to these external definitions. A new UI widget for theme items has also been added.

Changes

File(s) Change Summary
lib/app/app.dart Removed RepositoryProvider usage; updated bloc constructors to use diContainer.get() for dependency injection.
lib/di/di_initializer.config.dart, lib/di/di_repository_module.dart Added factory registration and factory method for providing EmailListRepository from the DI container.
lib/repository/email_list_repository.dart Changed EmailListRepository into an abstract class; added a loadData() method contract and a concrete EmailListRepositoryImpl implementation.
test/repository/email_list_repository_test.dart Modified test case to use a mocked EmailListRepository instance for invoking loadData().
lib/bloc/theme/theme_cubit.dart, lib/theme/style.dart Updated theme mappings; removed old color scheme methods and delegated theme creation to external theme classes (YellowTheme, OrangeTheme) with new brown theme methods added.
lib/theme/brown/brown_theme.dart, lib/theme/orange/orange_theme.dart, lib/theme/yellow/yellow_theme.dart Introduced new theme classes with static methods returning specific ColorScheme configurations for light and dark themes.
lib/theme/color_family.dart, lib/theme/extended_color.dart Added new classes (ColorFamily, ExtendedColor) for managing and comparing theme color properties using Equatable.
lib/features/settings/theme_item.dart Introduced a new ThemeItem widget that currently returns a constant placeholder widget.
pubspec.yaml Modified a configuration line related to flutter_intl (formatting change with no functional impact).

Sequence Diagram(s)

sequenceDiagram
  participant App as Application
  participant DI as diContainer
  participant Repo as EmailListRepositoryImpl
  participant Bloc as EmailListBloc

  App->>DI: Request EmailListRepository
  DI-->>App: Provide EmailListRepositoryImpl instance
  App->>Bloc: Instantiate EmailListBloc with repository
  Bloc->>Repo: Invoke loadData()
  Repo-->>Bloc: Return sorted email list
Loading
sequenceDiagram
  participant UI as UI Component
  participant Cubit as ThemeCubit
  participant Material as MaterialTheme
  participant Theme as BrownTheme

  UI->>Cubit: Request theme update (e.g., AppTheme.lightMint)
  Cubit->>Material: Call brownLight()
  Material->>Theme: brownLightScheme()
  Theme-->>Material: Return light ColorScheme for brown theme
  Material-->>Cubit: Return ThemeData
  Cubit-->>UI: Provide updated ThemeData
Loading

Poem

I’m a little rabbit, hopping with code so bright,
DI and themes now make my paths light.
No more old-context trails in the burrow of apps,
Direct injections and color schemes fill all the gaps.
With brown, orange, and yellow dancing in view,
My coding warren sings a tune fresh and new!
Leap on, dear code, with joy ever true!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a77dbf3 and bab3cc4.

📒 Files selected for processing (1)
  • test/repository/email_list_repository_test.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/repository/email_list_repository_test.dart
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: App

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
lib/theme/brown/brown_theme.dart (1)

3-309: Well-structured theme implementation.

The BrownTheme class provides a comprehensive set of color schemes for different brightness levels and contrast requirements. The code is well-organized and follows a consistent pattern for defining color schemes.

One suggestion to consider for future improvements would be to extract common color values into constants to reduce duplication, especially for colors that appear in multiple schemes.

lib/theme/orange/orange_theme.dart (2)

3-7: Inconsistent class design compared to BrownTheme.

Unlike BrownTheme, OrangeTheme accepts a TextTheme in its constructor and stores it as a member variable, but it's not used in any of the static methods. Consider either:

  1. Making the methods non-static and using the textTheme member variable, or
  2. Removing the constructor and textTheme field to make it consistent with BrownTheme
-class OrangeTheme {
-  OrangeTheme(this.textTheme);
-
-  final TextTheme textTheme;
+class OrangeTheme {

8-313: Inconsistent method naming convention.

The method naming convention in OrangeTheme (e.g., orangeLightScheme()) differs from BrownTheme (e.g., lightScheme()). This inconsistency can make the API less intuitive. Consider standardizing the naming convention across all theme classes for better maintainability.

For example, rename methods to match BrownTheme's convention:

-static ColorScheme orangeLightScheme() {
+static ColorScheme lightScheme() {

And similarly for the other methods.

lib/theme/yellow/yellow_theme.dart (3)

3-53: Consider reducing duplication or adding documentation.

The yellowLightScheme() function is quite verbose. You could reduce duplication across similar methods (e.g. grouping shared values, extracting a helper) or add brief doc comments explaining the purpose of specific color sets to improve maintainability.


157-206: Optional doc comments could improve clarity.

The yellowDarkScheme() function seems correct. A short explanation describing the intent (e.g., usage scenario, recommended background color) can help newer developers.


208-257: Possible candidate for reduced repetition or a single parameterized function.

yellowDarkMediumContrastScheme() replicates many values from other variants, which can lead to duplication. Consider a pattern to share common color definitions across your theme variants.

lib/theme/style.dart (1)

36-36: Possible redundant comment.

The //BrownTheme comment may be superfluous since the method names themselves convey that these are Brown theme variants. Consider removing it if it doesn’t add clarity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c83ba7 and a77dbf3.

📒 Files selected for processing (14)
  • lib/app/app.dart (1 hunks)
  • lib/bloc/theme/theme_cubit.dart (1 hunks)
  • lib/di/di_initializer.config.dart (3 hunks)
  • lib/di/di_repository_module.dart (2 hunks)
  • lib/features/settings/theme_item.dart (1 hunks)
  • lib/repository/email_list_repository.dart (1 hunks)
  • lib/theme/brown/brown_theme.dart (1 hunks)
  • lib/theme/color_family.dart (1 hunks)
  • lib/theme/extended_color.dart (1 hunks)
  • lib/theme/orange/orange_theme.dart (1 hunks)
  • lib/theme/style.dart (1 hunks)
  • lib/theme/yellow/yellow_theme.dart (1 hunks)
  • pubspec.yaml (1 hunks)
  • test/repository/email_list_repository_test.dart (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: CI
test/repository/email_list_repository_test.dart

[error] 34-34: MissingStubError: 'loadData'. No stub was found which matches the arguments of this method call: loadData(). Add a stub for this method using Mockito's 'when' API, or generate the MockEmailListRepository mock with the @GenerateNiceMocks annotation.

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (25)
pubspec.yaml (1)

98-98: No effective change in Flutter intl configuration

The line appears to be unchanged in terms of functionality, as it remains enabled: true before and after the changes.

lib/theme/color_family.dart (1)

5-25: Good implementation of ColorFamily class with proper value equality

The ColorFamily class is well-structured and follows good practices:

  • Uses Equatable for value-based equality
  • Has properly documented required parameters
  • Follows immutable pattern with final fields
  • Includes all properties in the props list for equality comparison

This will provide a strong foundation for your theme system refactoring, enabling consistent color definitions across different themes.

lib/di/di_repository_module.dart (2)

3-3: Added import for EmailListRepository

The import statement correctly brings in the necessary EmailListRepository class.


14-16:

✅ Verification successful

Properly registered EmailListRepository in DI container

The implementation correctly uses the @factoryMethod annotation to register the EmailListRepositoryImpl as the implementation for EmailListRepository interface. This follows dependency injection best practices by:

  1. Allowing the interface to be injected rather than the concrete implementation
  2. Using the factory method pattern for creating instances
  3. Maintaining consistency with other repository registrations in this file

🏁 Script executed:

#!/bin/bash
# Check if EmailListRepository is properly implemented as an abstract class
# with EmailListRepositoryImpl as its concrete implementation

echo "Checking EmailListRepository implementation:"
rg -A 10 "abstract class EmailListRepository" 
echo "Checking EmailListRepositoryImpl implementation:"
rg -A 10 "class EmailListRepositoryImpl implements EmailListRepository"

Length of output: 1647


DI Registration Verified: The EmailListRepository is Registered Correctly

  • The interface and implementation are defined as expected in lib/repository/email_list_repository.dart:
    • EmailListRepository is correctly declared as an abstract class.
    • EmailListRepositoryImpl properly implements the interface.
  • The DI registration in lib/di/di_repository_module.dart uses the @factoryMethod annotation to provide EmailListRepositoryImpl for the EmailListRepository interface, following dependency injection best practices.

The verification confirms that the current implementation correctly follows the intended DI pattern. No further changes are needed.

lib/bloc/theme/theme_cubit.dart (2)

12-12: Theme mapping updated for lightMint

The theme mapping for AppTheme.lightMint has been changed from using yellowLightMediumContrast() to brownLight(), which aligns with the new theme refactoring approach. This change is consistent with the PR objective of refactoring themes.


15-16: Theme mappings updated for darkMint and experimental themes

The theme mappings have been appropriately updated:

  • AppTheme.darkMint now uses brownDark() instead of yellowDarkMediumContrast()
  • AppTheme.experimental now uses yellowDark() instead of yellowDarkMediumContrast()

These changes are part of the broader theme system refactoring which appears to organize color schemes into more specific theme classes.

lib/theme/extended_color.dart (1)

6-37: Well-structured ExtendedColor class for theme management

The newly added ExtendedColor class provides a comprehensive structure for managing colors across different theme modes and contrast levels. It appropriately extends Equatable for value equality comparison and includes all necessary properties for the theme system refactoring.

The class design follows good practices:

  • Clear constructor with required parameters
  • Proper field declarations
  • Overridden props getter for equality comparison

This is a good addition to the theme system that will help manage colors consistently.

lib/di/di_initializer.config.dart (4)

24-25: Added import for EmailListRepository

The import for EmailListRepository has been properly added to support the dependency injection registration.


48-48: Repositioned DIDataModule declaration

The declaration of dIDataModule has been moved but maintains its functionality.


51-53: Added dependency injection for EmailListRepository

The factory registration for EmailListRepository has been added to the dependency injection container. This aligns with the broader refactoring to move from context-based repository providers to direct retrieval via dependency injection.


74-74: Repositioned DIDataModule class declaration

The class declaration for _$DIDataModule has been repositioned without functional changes.

lib/repository/email_list_repository.dart (2)

6-8: Good use of abstraction to improve design.

The introduction of an abstract EmailListRepository class establishes a clear contract through the loadData() method, which is a good application of the dependency inversion principle. This abstraction will make it easier to test and potentially implement alternative data sources in the future.


10-17: Implementation looks good.

The concrete implementation EmailListRepositoryImpl properly implements the interface and maintains the original functionality. This refactoring allows for better separation of concerns and improves testability.

lib/app/app.dart (2)

34-35: DI approach improved with direct container retrieval.

Good refactoring from context-based repository retrieval to direct dependency injection with diContainer.get<EmailListRepository>(). This approach is more explicit and removes the dependency on the BuildContext for retrieving repositories.


41-42: Consistent DI pattern application.

The same container-based DI approach is correctly applied here for the LaunchesRepository, maintaining consistency throughout the codebase.

lib/theme/yellow/yellow_theme.dart (3)

55-104: Looks good overall.

The yellowLightMediumContrastScheme() method follows the same structure as the light scheme. No issues spotted; contrast values appear logically consistent. Consider adding doc comments for clarity.


106-155: All good.

The yellowLightHighContrastScheme() is properly defined, with no evident errors. This keeps the code style consistent.


259-309: Implementation is consistent with the rest.

The yellowDarkHighContrastScheme() approach is aligned with the other theme definitions. No further issues noted.

lib/theme/style.dart (7)

2-5: Imports look appropriate.

These newly added imports correctly reference the new theme files. No concerns here.


13-13: Straightforward usage of the new theme method.

yellowLight() correctly delegates to YellowTheme.yellowLightScheme(). No issues found.


17-17: Proper dark scheme usage.

yellowDark() calls YellowTheme.yellowDarkScheme(). This follows the expected pattern.


21-21: Implementation aligns with new OrangeTheme.

orangeLight() correctly references OrangeTheme.orangeLightScheme(). No concerns.


25-25: Dark variant usage is consistent.

orangeDark() references OrangeTheme.orangeDarkScheme() in a similar manner. Looks good.


28-29: Brown dark theme logic is fine.

brownDark() simply delegates to BrownTheme.darkScheme(). No issues spotted.


32-33: Brown light theme logic is fine.

brownLight() calls BrownTheme.lightScheme(). This matches the established pattern.

Comment on lines +3 to +10
class ThemeItem extends StatelessWidget {
const ThemeItem({super.key});

@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

ThemeItem widget is incomplete and needs implementation details

The current implementation uses a Placeholder widget, which is only meant for development and not for production use. For a proper theme item widget in a settings screen, you should:

  1. Include properties to represent theme data (name, colors, etc.)
  2. Implement a visual preview of the theme
  3. Add selection mechanism (typically with a radio button or highlight)
  4. Connect to the theme system for actual theme switching

Consider implementing a more complete version:

 class ThemeItem extends StatelessWidget {
-  const ThemeItem({super.key});
+  const ThemeItem({
+    super.key,
+    required this.themeName,
+    required this.isSelected,
+    required this.onSelect,
+    required this.themeColor,
+  });
+
+  final String themeName;
+  final bool isSelected;
+  final VoidCallback onSelect;
+  final Color themeColor;

   @override
   Widget build(BuildContext context) {
-    return const Placeholder();
+    return InkWell(
+      onTap: onSelect,
+      child: Container(
+        padding: const EdgeInsets.all(16),
+        decoration: BoxDecoration(
+          border: Border.all(
+            color: isSelected ? themeColor : Colors.grey.shade300,
+            width: isSelected ? 2 : 1,
+          ),
+          borderRadius: BorderRadius.circular(8),
+        ),
+        child: Row(
+          children: [
+            Container(
+              width: 24,
+              height: 24,
+              decoration: BoxDecoration(
+                color: themeColor,
+                shape: BoxShape.circle,
+              ),
+            ),
+            const SizedBox(width: 16),
+            Text(themeName),
+            const Spacer(),
+            if (isSelected)
+              Icon(Icons.check_circle, color: themeColor),
+          ],
+        ),
+      ),
+    );
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class ThemeItem extends StatelessWidget {
const ThemeItem({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
import 'package:flutter/material.dart';
class ThemeItem extends StatelessWidget {
const ThemeItem({
super.key,
required this.themeName,
required this.isSelected,
required this.onSelect,
required this.themeColor,
});
final String themeName;
final bool isSelected;
final VoidCallback onSelect;
final Color themeColor;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onSelect,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
border: Border.all(
color: isSelected ? themeColor : Colors.grey.shade300,
width: isSelected ? 2 : 1,
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: themeColor,
shape: BoxShape.circle,
),
),
const SizedBox(width: 16),
Text(themeName),
const Spacer(),
if (isSelected) Icon(Icons.check_circle, color: themeColor),
],
),
),
);
}
}

Copy link

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
-4.04% (target: -1.00%) 34.69%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (7c83ba7) 783 501 63.98%
Head commit (bab3cc4) 794 (+11) 476 (-25) 59.95% (-4.04%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#3) 49 17 34.69%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Codacy stopped sending the deprecated coverage status on June 5th, 2024. Learn more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant