Skip to content

feat: adding different font styles #1351

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 30 commits into
base: development
Choose a base branch
from

Conversation

nope3472
Copy link
Contributor

@nope3472 nope3472 commented Jun 24, 2025

Summary

Add a font‐picker button to the HomeScreen text field so users can choose and apply Google Fonts in real time.

Changes

  • UI: Inserted a font‐icon button alongside the HomeScreen text field.
  • Dialog: Integrated the existing FontPickerDialog for selecting fonts.
  • Live Preview: When a font is picked, the text field’s style updates immediately via the google_fonts package.

Checklist

  • No hard-coded values; all resources come from constants.dart.
  • No modifications at the end of any resource files.
  • Code reformatted and indentation corrected.
  • All static analysis and tests pass (flutter analyze & flutter test).

images

WhatsApp Image 2025-06-26 at 15 36 12
WhatsApp Image 2025-06-26 at 15 36 09

Summary by Sourcery

Add a font picker to the HomeScreen text field and extend badge persistence and editing capabilities, while improving file handling and data management utilities.

New Features:

  • Integrate a FontPickerDialog with Google Fonts for live font selection in the home screen text field
  • Allow HomeScreen to load and edit existing saved badges by applying JSON data (text, effects, speed, mode)
  • Introduce BadgeTextStorage to persist and retrieve original badge texts

Enhancements:

  • Refactor SavedBadgeProvider to add applySavedBadgeDataToUI and updateBadgeData methods for managing saved badge lifecycle
  • Improve FileHelper with synchronized file access, unified cache updates, and resilient JSON parsing with missing-key fallbacks
  • Simplify animation provider with a clearAllEffects method and streamline speed value derivation

Build:

  • Add synchronized package dependency

Chores:

  • Refactor save_badge_card widget for safe data access and navigation to HomeScreen for editing

Copy link
Contributor

sourcery-ai bot commented Jun 24, 2025

Reviewer's Guide

This PR integrates a Google Fonts–based font picker into the HomeScreen text field for real-time style updates, extends badge editing by loading and updating saved badge files, and strengthens file I/O and data persistence through synchronization and utility classes.

Sequence diagram for editing a saved badge with font and effect restoration

sequenceDiagram
    actor User
    participant HomeScreen
    participant FileHelper
    participant BadgeTextStorage
    participant AnimationBadgeProvider
    participant SpeedDialProvider
    User->>HomeScreen: Open HomeScreen with savedBadgeFilename
    HomeScreen->>FileHelper: Load badge JSON from disk
    FileHelper-->>HomeScreen: Return badge data
    HomeScreen->>BadgeTextStorage: Get original text for badge
    BadgeTextStorage-->>HomeScreen: Return original text
    HomeScreen->>AnimationBadgeProvider: Set effects and animation mode
    HomeScreen->>SpeedDialProvider: Set speed dial value
    HomeScreen->>HomeScreen: Set text field to original text
    User->>HomeScreen: Edit and save badge
    HomeScreen->>SavedBadgeProvider: updateBadgeData(...)
    SavedBadgeProvider->>FileHelper: Save updated badge data
    SavedBadgeProvider->>BadgeTextStorage: Save updated original text
    FileHelper-->>SavedBadgeProvider: Confirm save
    BadgeTextStorage-->>SavedBadgeProvider: Confirm save
    SavedBadgeProvider-->>HomeScreen: Confirm update
    HomeScreen-->>User: Show "Badge Updated Successfully"
Loading

Class diagram for new and updated types: FontPickerDialog, BadgeTextStorage, SavedBadgeProvider

classDiagram
    class FontPickerDialog {
      +String? selectedFont
      +ValueChanged<String?> onFontSelected
      +build(BuildContext context)
    }
    class BadgeTextStorage {
      <<static>>
      +saveOriginalText(String badgeFilename, String originalText)
      +getOriginalText(String badgeFilename)
      +deleteOriginalText(String badgeFilename)
    }
    class SavedBadgeProvider {
      +applySavedBadgeDataToUI(...)
      +updateBadgeData(...)
      +getBadgeData(...)
      +savedBadgeAnimation(...)
      +isSavedBadgeData: bool
      +setSavedBadgeDataMap(...)
      +setIsSavedBadgeData(...)
    }
    FontPickerDialog --|> StatelessWidget
    SavedBadgeProvider --|> ChangeNotifier
Loading

File-Level Changes

Change Details Files
Integrated a real-time font picker into the HomeScreen text field
  • Added _selectedFontFamily state and imported google_fonts
  • Added suffixIcon with FontPickerDialog invocation
  • Applied GoogleFonts.getFont(_selectedFontFamily) to ExtendedTextField style
  • Loaded initial font selection and persisted on user choice
lib/view/homescreen.dart
Created a standalone FontPickerDialog component
  • Defined fontOptions map of human‐readable names to Google Font keys
  • Built an AlertDialog with RadioListTile for selection
  • Returned selected font via Navigator.pop
lib/view/font-picker.dart
Refactored SavedBadgeProvider to support editing existing badges
  • Extracted applySavedBadgeDataToUI to populate UI from JSON
  • Added updateBadgeData method to overwrite existing files and caches
  • Moved text retrieval to BadgeTextStorage and notify via Toast
lib/providers/saved_badge_provider.dart
Strengthened FileHelper with synchronization and cache management
  • Introduced a static Lock for read/write/delete operations
  • Wrapped file I/O in synchronized blocks
  • Extracted cache updates into _updateSavedBadgeCache helper
  • Enhanced jsonToData error handling for missing keys
lib/bademagic_module/utils/file_helper.dart
Added BadgeTextStorage utility for original text persistence
  • Implemented save/get/delete methods backed by a JSON file
  • Stored original badge text alongside badge data
  • Used path_provider to locate app documents directory
lib/bademagic_module/utils/badge_text_storage.dart
Minor refactors and data-access safety enhancements
  • Simplified Speed.getIntValue to use enum index
  • Added clearAllEffects in AnimationBadgeProvider
  • Replaced direct JSON access in SaveBadgeCard with safe getters
lib/providers/animation_badge_provider.dart
lib/bademagic_module/models/speed.dart
lib/view/widgets/save_badge_card.dart

Possibly linked issues

  • #0: The PR adds a font picker and applies selected Google Fonts to the text preview, implementing the font support requested in the issue.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @nope3472 - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `lib/view/homescreen.dart:540` </location>
<code_context>
+    if (state == AppLifecycleState.resumed) {
+      inlineimagecontroller.clear();
+      previousText = '';
+      animationProvider.stopAllAnimations.call(); // If method exists
+      animationProvider.initializeAnimation.call(); // If method exists
+      if (mounted) setState(() {});
+    } else if (state == AppLifecycleState.paused ||
</code_context>

<issue_to_address>
Calling methods with .call() may cause runtime errors if not callable.

Using `.call()` here will throw if these are standard methods. Invoke them directly as methods instead.
</issue_to_address>

### Comment 2
<location> `lib/view/homescreen.dart:270` </location>
<code_context>
+                          onChanged: (value) {},
+                          controller: inlineimagecontroller,
+                          specialTextSpanBuilder: ImageBuilder(),
+                          style: _selectedFontFamily != null
+                              ? GoogleFonts.getFont(_selectedFontFamily!)
+                              : null,
+                          decoration: InputDecoration(
+                            border: OutlineInputBorder(
</code_context>

<issue_to_address>
No fallback for invalid or unavailable font family.

Validate _selectedFontFamily or add a fallback to avoid exceptions if the font is unsupported.
</issue_to_address>

### Comment 3
<location> `lib/bademagic_module/utils/file_helper.dart:203` </location>
<code_context>
+  /// Save the original text for a badge
+  static Future<void> saveOriginalText(
+      String badgeFilename, String originalText) async {
+    try {
+      // Get the existing text storage or create a new one
+      Map<String, String> textStorage = await _getTextStorage();
</code_context>

<issue_to_address>
Logging uses info level for errors.

Use `logger.e` for error messages to clearly indicate error-level events instead of `logger.i`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +540 to +541
animationProvider.stopAllAnimations.call(); // If method exists
animationProvider.initializeAnimation.call(); // If method exists
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Calling methods with .call() may cause runtime errors if not callable.

Using .call() here will throw if these are standard methods. Invoke them directly as methods instead.

Comment on lines 270 to 272
style: _selectedFontFamily != null
? GoogleFonts.getFont(_selectedFontFamily!)
: null,
Copy link
Contributor

Choose a reason for hiding this comment

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

issue: No fallback for invalid or unavailable font family.

Validate _selectedFontFamily or add a fallback to avoid exceptions if the font is unsupported.

Comment on lines 203 to 212
try {
final path = await _getFilePath(filename);
final file = File(path);

if (await file.exists()) {
final content = await file.readAsString();
final dynamic decodedData = jsonDecode(content);

// Automatically return decoded JSON as a dynamic type
return decodedData;
} else {
logger.d('File not found: $filename');
return null;
}
return await _badgeFileLock.synchronized(() async {
if (await file.exists()) {
final content = await file.readAsString();
return jsonDecode(content);
} else {
logger.i('File not found: $path');
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: Logging uses info level for errors.

Use logger.e for error messages to clearly indicate error-level events instead of logger.i.

Copy link
Contributor

github-actions bot commented Jun 24, 2025

Build Status

Build successful. APKs to test: https://github.com/fossasia/badgemagic-app/actions/runs/16571151071/artifacts/3629966034.

Screenshots (Android)

Screenshots (iPhone)

Screenshots (iPad)

@samruddhi-Rahegaonkar
Copy link
Member

samruddhi-Rahegaonkar commented Jun 24, 2025

@nope3472 will you add recording or image for the output ?

@mariobehling mariobehling self-requested a review July 14, 2025 06:00
Copy link
Member

@mariobehling mariobehling left a comment

Choose a reason for hiding this comment

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

Please check the following

  1. Code structure and maintainability: The font-handling logic is directly embedded within core UI or rendering code, making it difficult to maintain or extend. Recommendation:
  • Move font-specific logic (e.g., style detection, hex generation) into a dedicated utility or service class.
  • Keep the UI code focused on layout and user interaction, not logic processing.
  1. Lack of inline documentation: There are no comments explaining how the font style logic works, especially for the hex string generation and bitmap handling. Recommendation:
  • Add /// comments above all public methods and non-obvious logic blocks.
  • Document the font support limitations (e.g., resolution, character set constraints).
  1. Hardware constraints not accounted for
    Based on prior discussion, some fonts clip or render indistinctly due to badge resolution limits. However, these limitations are not surfaced in the code or PR description. Clarify, how could this be handled, e.g. Would it be suitable to add conditionals or UI warnings if unsupported font styles are selected?

  2. Missing tests: No unit or integration tests are provided to verify the font conversion logic or UI state handling. Recommendation:

  • Add test coverage for font selection logic.
  • Test fallback behavior if a font cannot be applied.
  1. PR Description: Add the issue that is fixed into the PR description.

@nope3472
Copy link
Contributor Author

hey @Vishveshwara thank for pointing this out i have fixed your concerns and here is how i am using json to save the text-
We use JSON to save all badge data, including the text, effects, speed, and animation settings. This makes it easy to store, load, and share badges. The text is saved as a list of hex strings (representing the LED grid for each character or segment), along with all other badge properties, in a single JSON file.

@nope3472
Copy link
Contributor Author

@nope3472 any progress here?

yes now the fontstyles are more accurate and gets transferred to the badge correctly

@nope3472
Copy link
Contributor Author

@Vishveshwara there will be some fonts which will not be able to render the characters correctly due to our 11x8 logic.

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar self-requested a review July 25, 2025 04:27
Copy link
Member

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar left a comment

Choose a reason for hiding this comment

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

@nope3472 this is causing due to CI/CD

@samruddhi-Rahegaonkar
Copy link
Member

@AsCress What do you think cause of this ?

@nope3472
Copy link
Contributor Author

@samruddhi-Rahegaonkar yeah will do the changes

@samruddhi-Rahegaonkar
Copy link
Member

@nope3472 here the failing CIs cause is not you code i guess, its something related to CI/CD

@AsCress
Copy link
Contributor

AsCress commented Jul 25, 2025

@nope3472 @samruddhi-Rahegaonkar This is fine. Just rebase. Seems like the test was canceled due to some reason.

@samruddhi-Rahegaonkar
Copy link
Member

@nope3472 the font Montserrat, Raleway is not working properly please remove it instead of adding multiple font styles lets focus which could be render good on badge.

@samruddhi-Rahegaonkar
Copy link
Member

@nope3472 After saving badges the font is not saving and in saved badges its rendering as normal font.

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar self-requested a review July 26, 2025 15:45
Copy link
Member

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar left a comment

Choose a reason for hiding this comment

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

@nope3472 Please do the changes.

@Jhalakupadhyay
Copy link
Contributor

@nope3472 please make sure that I see the changes related to current issue only there are a lot of changes that are not related to current issue.

Copy link
Member

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar left a comment

Choose a reason for hiding this comment

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

@nope3472 Please update the branch and clean up the commits to include only changes related to this PR. Once done, we're good to go. Thanks!

Copy link
Member

@samruddhi-Rahegaonkar samruddhi-Rahegaonkar left a comment

Choose a reason for hiding this comment

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

@nope3472 @hpdang this is good as we are starting but the font styles are not rendering properly we need to improve font rendering but for now i think we can go with this as of now but need changes also @nope3472 The message of some characters might get cutoff due to badge size for evry font style seems to be irritating make a toast message little bit small and only for font styles in which characters get actually cut-off.

@hpdang What do you think ?

@Vishveshwara
Copy link
Contributor

Vishveshwara commented Jul 29, 2025

@nope3472 @hpdang this is good as we are starting but the font styles are not rendering properly we need to improve font rendering but for now i think we can go with this as of now but need changes also @nope3472 The message of some characters might get cutoff due to badge size for evry font style seems to be irritating make a toast message little bit small and only for font styles in which characters get actually cut-off.

@hpdang What do you think ?

@nope3472 we should not have the toast message at all, no one would like to use fonts which gets cut off , its better to only support the fonts which are getting rendered properly.

@nope3472
Copy link
Contributor Author

@samruddhi-Rahegaonkar @Vishveshwara okay i will recheck this toastmessage

@samruddhi-Rahegaonkar
Copy link
Member

@nope3472 @hpdang this is good as we are starting but the font styles are not rendering properly we need to improve font rendering but for now i think we can go with this as of now but need changes also @nope3472 The message of some characters might get cutoff due to badge size for evry font style seems to be irritating make a toast message little bit small and only for font styles in which characters get actually cut-off.
@hpdang What do you think ?

@nope3472 we should not have the toast message at all, no one would like to use fonts which gets cut off , its better to only support the fonts which are getting rendered properly.

@Vishveshwara Absolutely Correct!

@samruddhi-Rahegaonkar
Copy link
Member

@nope3472 Most of the fonts are not rendered properly.

@nope3472
Copy link
Contributor Author

nope3472 commented Jul 29, 2025

@samruddhi-Rahegaonkar the hexstring that gets generated from the logic i have checked them and when we convert them into 8 bit strings they are generating a image of the characters correctly but the constraints are blocking them

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

Successfully merging this pull request may close these issues.

7 participants