Skip to content

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 439
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 158
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/17009673723/artifacts/3779983603.

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 ?

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

@mariobehling sure i will add the warning for specific fonts and will add the comments for the understanding

segments.add({'type': 'text', 'content': currentText});
}

// If using default font, return per-character hexes (old behavior)
Copy link
Contributor

Choose a reason for hiding this comment

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

@nope3472 as per our last talk we want to get rid of the maps that we have already but I can see them getting used here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Jhalakupadhyay i was thinking that as we have limitation with few characters provided in our current firmware size so we keep it as backup like is any character required more than alloted space we can fallback to this default.

pubspec.yaml Outdated
@@ -51,6 +51,7 @@ dependencies:
google_fonts: ^6.2.1
url_launcher: ^6.3.1
image: ^4.5.4
synchronized: ^3.3.1
Copy link
Contributor

Choose a reason for hiding this comment

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

@nope3472 If we are not using them please remove the dependency from here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Jhalakupadhyay yeah sure

Copy link
Contributor

Choose a reason for hiding this comment

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

@nope3472 and also as per our previous talk we wanted to get rid of the existing map I can still see we are using it here.

@hpdang
Copy link
Member

hpdang commented Jul 17, 2025

@nope3472 this #1259 also adds support for different fonts. Please review it and enhance your implementation of font support accordingly. Check the method used to read the fontStyle, how it is sent to the badge, whether the transfer works correctly, and which font styles are currently implemented. Also, consider which logic can be applied to make it easier to add new fonts in the future.

@hpdang
Copy link
Member

hpdang commented Jul 21, 2025

@nope3472 any progress here?

@Vishveshwara
Copy link
Contributor

@nope3472 @hpdang

  • the character's font thickness should be adjusted , so that the font can be visible, many characters are not visible clearly
  • and then the font in the message is not changing when the font is changed, it only changes when i add or remove a text

I see that you are creating a saved text feature, I think its better to create a seperate issue for this. Do you mind explaining me how you are using json to save the text

vivek.download.mp4

@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

@hpdang
Copy link
Member

hpdang commented Aug 4, 2025

@nope3472 please check if any font supports chinese characters

@samruddhi-Rahegaonkar
Copy link
Member

samruddhi-Rahegaonkar commented Aug 6, 2025

@nope3472 Please add recordings for the new changes or lets review in tommorows meeting anything can work.
lets finalise this PR by tommorow.

@hpdang
Copy link
Member

hpdang commented Aug 8, 2025

@samruddhi-Rahegaonkar can you please review?

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.

LGTM !

@hpdang
Copy link
Member

hpdang commented Aug 11, 2025

@nope3472 please resolve conflict

@nope3472
Copy link
Contributor Author

@hpdang i have resolved the conflicts

@mariobehling mariobehling merged commit 947353a into fossasia:development Aug 17, 2025
6 checks passed
hpdang pushed a commit that referenced this pull request Aug 18, 2025
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