-
Notifications
You must be signed in to change notification settings - Fork 46
feat: Enhanced UI and Functionality for the Select Screen #18
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "displays": [ | ||
| { | ||
| "id": "epaper-3.7-bwr", | ||
| "model": "GDEY037Z03", | ||
| "name": "E-Paper 3.7\"", | ||
| "size": 3.7, | ||
| "resolution": [416, 240], | ||
| "colors": ["black", "white", "red"], | ||
| "driver": "UC8253", | ||
| "imagePath": "assets/images/displays/epaper_3.7_bwr.png", | ||
| "epdClass": "Gdey037z03" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, how is this approach scalable, when we are anyways creating a new class for any new display that we want to add ? |
||
| }, | ||
| { | ||
| "id": "epaper-3.7-bw", | ||
| "model": "GDEY037T03", | ||
| "name": "E-Paper 3.7\"", | ||
| "size": 3.7, | ||
| "resolution": [416, 240], | ||
| "colors": ["black", "white"], | ||
| "driver": "UC8253", | ||
| "imagePath": "assets/images/displays/epaper_3.7_bw.PNG", | ||
| "epdClass": "Gdey037z03BW" | ||
| } | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,14 @@ | ||
| import 'package:flutter/material.dart'; | ||
| import 'package:magic_epaper_app/provider/image_loader.dart'; | ||
| import 'package:magic_epaper_app/provider/display_provider.dart'; | ||
| import 'package:provider/provider.dart'; | ||
|
|
||
| import 'package:magic_epaper_app/view/home_screen.dart'; | ||
| import 'package:magic_epaper_app/view/display_selection_screen.dart'; | ||
|
|
||
| void main() { | ||
| runApp(MultiProvider(providers: [ | ||
| ChangeNotifierProvider(create: (context) => ImageLoader()), | ||
| ChangeNotifierProvider(create: (context) => DisplayProvider()), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| ], child: const MyApp())); | ||
| } | ||
|
|
||
|
|
@@ -21,7 +23,7 @@ class MyApp extends StatelessWidget { | |
| useMaterial3: true, | ||
| colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange), | ||
| ), | ||
| home: const SelectDisplay(), | ||
| home: const DisplaySelectionScreen(), | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import 'dart:math'; | ||
| import 'package:flutter/material.dart'; | ||
| import 'package:magic_epaper_app/util/epd/edp.dart'; | ||
|
|
||
| class DisplayModel { | ||
| final String id; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having so many parameters for each display ( |
||
| final String name; | ||
| final String ModelName; // For future use | ||
| final double size; // Inches | ||
| final int width, height; // Pixels | ||
| final List<Color> colors; | ||
| final String driver; | ||
| final String imagePath; | ||
| final Epd epd; | ||
|
|
||
| // Constructor | ||
| DisplayModel({ | ||
| required this.id, | ||
| required this.name, | ||
| required this.size, | ||
| required this.width, | ||
| required this.height, | ||
| required this.colors, | ||
| required this.ModelName, | ||
| required this.driver, | ||
| required this.imagePath, | ||
| required this.epd, | ||
| }); | ||
|
|
||
| // Computed properties | ||
| bool get isColor => colors.length > 2; // More than black and white | ||
| bool get isHd => width >= 1280 && height >= 720; | ||
| double get ppi => sqrt(pow(width, 2) + pow(height, 2)) / size; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we use this anywhere ? |
||
|
|
||
| // Format aspect ratio | ||
| String get aspectRatio { | ||
| int gcd = _findGCD(width, height); | ||
| return '${width ~/ gcd}:${height ~/ gcd}'; | ||
| } | ||
|
|
||
| // Helper method to find GCD for aspect ratio calculation | ||
| int _findGCD(int a, int b) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why a separate function for |
||
| while (b != 0) { | ||
| int t = b; | ||
| b = a % b; | ||
| a = t; | ||
| } | ||
| return a; | ||
| } | ||
|
|
||
| // Get color names as a formatted string | ||
| String get colorNames { | ||
| final List<String> colorNames = []; | ||
|
|
||
| if (colors.contains(Colors.black)) colorNames.add('Black'); | ||
| if (colors.contains(Colors.white)) colorNames.add('White'); | ||
| if (colors.contains(Colors.red)) colorNames.add('Red'); | ||
| if (colors.contains(Colors.yellow)) colorNames.add('Yellow'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't have yellow anywhere in the displays. |
||
|
|
||
| return colorNames.join(', '); | ||
| } | ||
|
|
||
| // Format resolution as a string | ||
| String get resolution => '$width × $height'; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| import 'dart:convert'; | ||
| import 'package:flutter/material.dart'; | ||
| import 'package:flutter/services.dart'; | ||
| import 'package:magic_epaper_app/model/display_model.dart'; | ||
| import 'package:magic_epaper_app/util/epd/gdey037z03.dart'; | ||
| import 'package:magic_epaper_app/util/epd/gdey037z03bw.dart'; | ||
|
|
||
| class DisplayProvider extends ChangeNotifier { | ||
| // Filter options | ||
| String _activeFilter = 'All Displays'; | ||
| int _selectedDisplayIndex = -1; // -1 means no selection | ||
|
|
||
| // Getters | ||
| String get activeFilter => _activeFilter; | ||
| int get selectedDisplayIndex => _selectedDisplayIndex; | ||
| bool get hasSelection => _selectedDisplayIndex != -1; | ||
| DisplayModel? get selectedDisplay => | ||
| hasSelection ? filteredDisplays[_selectedDisplayIndex] : null; | ||
|
|
||
| // All filter options | ||
| final List<String> filterOptions = [ | ||
| 'All Displays', | ||
| 'Color', | ||
| 'Black & White', | ||
| 'HD', | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am assuming you are aware of the hardware that would interact with this app, right ? |
||
| ]; | ||
|
|
||
| // List of all available displays | ||
| List<DisplayModel> allDisplays = []; | ||
|
|
||
| // Constructor - Initialize by loading from JSON | ||
| DisplayProvider() { | ||
| loadDisplaysFromJson(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Asynchronous method inside constructor ? Maybe handle this in |
||
| } | ||
|
|
||
| // Load displays from JSON file | ||
| Future<void> loadDisplaysFromJson() async { | ||
| try { | ||
| // Load the JSON file from the assets | ||
| final String jsonString = | ||
| await rootBundle.loadString('assets/displays.json'); | ||
| final Map<String, dynamic> jsonData = json.decode(jsonString); | ||
|
|
||
| // Clear the existing displays | ||
| allDisplays = []; | ||
|
|
||
| // Parse the JSON data | ||
| for (var displayData in jsonData['displays']) { | ||
| // Convert colors from strings to Color objects | ||
| List<Color> colors = []; | ||
| for (var colorName in displayData['colors']) { | ||
| switch (colorName) { | ||
| case 'black': | ||
| colors.add(Colors.black); | ||
| break; | ||
| case 'white': | ||
| colors.add(Colors.white); | ||
| break; | ||
| case 'red': | ||
| colors.add(Colors.red); | ||
| break; | ||
| case 'yellow': | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for here. |
||
| colors.add(Colors.yellow); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| // Determine which EPD to use based on the class name | ||
| var epd = _getEpdForClassName(displayData['epdClass']); | ||
|
|
||
| // Create a DisplayModel from the JSON data | ||
| final display = DisplayModel( | ||
| id: displayData['id'], | ||
| name: displayData['name'], | ||
| size: displayData['size'], | ||
| ModelName: displayData['model'], | ||
| width: displayData['resolution'][0], | ||
| height: displayData['resolution'][1], | ||
| colors: colors, | ||
| driver: displayData['driver'], | ||
| imagePath: displayData['imagePath'], | ||
| epd: epd, | ||
| ); | ||
|
|
||
| allDisplays.add(display); | ||
| } | ||
|
|
||
| // Notify listeners that the data has changed | ||
| notifyListeners(); | ||
| } catch (e) { | ||
| print('Error loading displays from JSON: $e'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid having |
||
| } | ||
| } | ||
|
|
||
| // Helper method to get the appropriate EPD based on class name | ||
| dynamic _getEpdForClassName(String className) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another function which just increases complexity, if you're aiming for a scalable approach. |
||
| switch (className) { | ||
| case 'Gdey037z03': | ||
| return Gdey037z03(); | ||
| case 'Gdey037z03BW': | ||
| return Gdey037z03BW(); | ||
| default: | ||
| return Gdey037z03(); // Default fallback | ||
| } | ||
| } | ||
|
|
||
| // Get filtered displays based on the active filter | ||
| List<DisplayModel> get filteredDisplays { | ||
| switch (_activeFilter) { | ||
| case 'HD': | ||
| return allDisplays.where((display) => display.isHd).toList(); | ||
| case 'Color': | ||
| return allDisplays.where((display) => display.isColor).toList(); | ||
| case 'Black & White': | ||
| return allDisplays.where((display) => !display.isColor).toList(); | ||
| case 'All Displays': | ||
| default: | ||
| return allDisplays; | ||
| } | ||
| } | ||
|
|
||
| // Set the active filter | ||
| void setFilter(String filter) { | ||
| if (_activeFilter != filter) { | ||
| _activeFilter = filter; | ||
| // Reset selection when filter changes | ||
| _selectedDisplayIndex = -1; | ||
| notifyListeners(); | ||
| } | ||
| } | ||
|
|
||
| // Select a display | ||
| void selectDisplay(int index) { | ||
| if (index >= 0 && index < filteredDisplays.length) { | ||
| _selectedDisplayIndex = index; | ||
| notifyListeners(); | ||
| } | ||
| } | ||
|
|
||
| // Clear selection | ||
| void clearSelection() { | ||
| _selectedDisplayIndex = -1; | ||
| notifyListeners(); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would be actually needing JSON storage for this ? The number of displays that we have to interact with are very limited and we already have an abstract class
Epd, which is extended to model a display. Those classes could simply be modified to add whatever more parameters you want to show about the displays.