samedi 19 septembre 2020

Design pattern for subclassing widgets

I'm currently working on a guitar app. This app has several exercices type (find and play the correct displayed note, read music notations...). Each exercice type must return 2 widgets with their states :

  • a page to play the exercice

  • a page to customize the exercice (settings page) Each exercice type has each own unique page. For example, exercice A may need 2 TextField and exercice B may need 1 dropdown button. So far, I implemented it successfully with this pattern :

    I wrote an Exercice class (to store all exercices created by the user in a database) :

class Exercice {
    String name;
    int exerciceType;
    String exerciceSettings; // <-- stored in json
}

And I created this abstract class :

abstract class ExerciceType {
    int get id; // each exercice type has a unique type String get displayedName; Icon get icon;
    Widget settingWidgets(); // return the settings page String toJson();         // serialize settings from the settings page in a json string Widget playPage();       // return the page where we can play the exercice
}

And then, each exercices type can be implemented like this :

class FindNote extends ExerciceType {
    String displayedName = "find_note";
    int id = 0;
    Icon icon = Icon(Icons.audiotrack);
    // this is what concerned me the most, I have to pass the state here... :(
    FindNoteSettingsPage widgetSettings = FindNoteSettingsPage(state: _FindNoteSettingsPageState());
    FindNotePlayPage playPages = FindNotePlayPage(state: _FindNotePlayPageState());
    StatefulWidget settingWidgets() { return widgetSettings; }
    StatefulWidget playPage() { return playPages; }
    String toJson() {
        var settings = {};
        // :( bad things here I suppose... 
        settings["minFret"] = widgetSettings.state._values.start.toInt(); 
        settings["maxFret"] = widgetSettings.state._values.end.toInt(); 
        settings["strings"] = 
        widgetSettings.state.stringsList.stringActive;
        return json.encode(settings);
    }
}

class FindNoteSettingsPage extends StatefulWidget {
          final _FindNoteSettingsPageState state;
        
          FindNoteSettingsPage({Key key, @required this.state}) : super(key: key);
        
          @override
          _FindNoteSettingsPageState createState() {
            return state;
          }
}
        
class _FindNoteSettingsPageState extends State<FindNoteSettingsPage> {
           // some attributes here
        
          @override
          Widget build(BuildContext context) {
            return new Column(//my settings page here with TextField and so on.)
          }
}
        
// same pattern is used to implement the play page class

So far the code is working but I'm not satisfied with this design.

For example, if I want to show to the user his exercices list, each exercice must be instantiated completly (so loading each settings/play page, custom behavior...)

I will greatly appreciate any advices that can improve this design pattern. I suppose I'm not the first to write this kind of logic in Flutter :) Thanks in advance ! I can post a link to the Github repo for anyone requesting it.

Aucun commentaire:

Enregistrer un commentaire