Skip to content
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

Save & Restore Layout functionality #1

Closed
h3x4d3c1m4l opened this issue Nov 29, 2021 · 4 comments · Fixed by #39
Closed

Save & Restore Layout functionality #1

h3x4d3c1m4l opened this issue Nov 29, 2021 · 4 comments · Fixed by #39
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@h3x4d3c1m4l
Copy link

For a project it would be nice if I could save the layout the user created (to a file, or perhaps a byte array for storing in a database) and restore it again. It seems this is not possible at the moment, but I'm very much interested in building this myself :)

Do you have any thoughts (perhaps some pointers) on this?

@caduandrade caduandrade added the enhancement New feature or request label Nov 29, 2021
@caduandrade
Copy link
Owner

Hi! You are right. This functionality is required. It's on my TODO list.

Serialization (save)

Could be a method to get a String or a byte array as you said. I just think that some information should be present in the structure:

  • layoutId

This identifier does not have to be exactly the same as the one the developer will use for persistence.

  • layoutVersion

If the structure changes in the future, it may be possible to convert versions

  • itemId?

I would have to think about how we could identify which widget is created on each DockingItem. An identifier would work, but each application would have to maintain some mapping between identifier and Widget type (I'm ignoring Widget state to simplify the problem). Maybe there's no way to automatically cover everything.

DockingItem already allows a "value" (dynamic) that can be used in any way by the application. Using this value in serialization could override the need for the identifier but would make serialization itself difficult.

Deserialization (restore)

Could be a method whose parameter is a function (as a builder) to build the widgets given the solution defined to identify each DockingItem.

typedef WidgetDeserialization = Widget Function(dynamic itemId);
  void deserialize(String layout, WidgetDeserialization widgetDeserialization) {    
  }

Could be a layout factory as well. Build a new layout given the serialized layout.

I hope I'm not making the solution too difficult.

@vd3d
Copy link

vd3d commented Sep 12, 2023

Hello, any news of this feature? It will be a great nice to have :-)

Thx

@caduandrade
Copy link
Owner

Hi @vd3d!

I think I'd better do #23 first as it will impact this issue.

@caduandrade caduandrade self-assigned this Sep 14, 2023
@caduandrade caduandrade added this to the 1.14.0 milestone Sep 17, 2023
caduandrade added a commit that referenced this issue Sep 25, 2023
caduandrade added a commit that referenced this issue Sep 25, 2023
caduandrade added a commit that referenced this issue Sep 25, 2023
caduandrade added a commit that referenced this issue Sep 28, 2023
caduandrade added a commit that referenced this issue Sep 28, 2023
caduandrade added a commit that referenced this issue Sep 28, 2023
caduandrade added a commit that referenced this issue Oct 12, 2023
@caduandrade
Copy link
Owner

caduandrade commented Oct 16, 2023

Final version.

Core API:

/// Parser between DockingLayout and String.
abstract class LayoutParser {
  const LayoutParser();

  /// Converts ID to String.
  String idToString(dynamic id);

  /// Converts String to ID.
  dynamic stringToId(String id);
}

mixin LayoutParserMixin implements LayoutParser {

  /// Default conversion from ID to String.
  String idToString(dynamic id) {
    return id == null ? '' : id.toString();
  }

  /// Default conversion from String to ID.
  dynamic stringToId(String id) {
    return id == '' ? null : id;
  }
}
abstract class AreaBuilder {

  /// Builds a [DockingItem].
  DockingItem buildDockingItem(
      {required dynamic id, required double? weight, required bool maximized});

  /// Builds a [DockingRow].
  DockingRow buildDockingRow(
      {required dynamic id,
      required double? weight,
      required List<DockingArea> children});

  /// Builds a [DockingColumn].
  DockingColumn buildDockingColumn(
      {required dynamic id,
      required double? weight,
      required List<DockingArea> children});

  /// Builds a [DockingTabs].
  DockingTabs buildDockingTabs(
      {required dynamic id,
      required double? weight,
      required bool maximized,
      required List<DockingItem> children});
}

mixin AreaBuilderMixin implements AreaBuilder {

  DockingRow buildDockingRow(
      {required dynamic id,
      required double? weight,
      required List<DockingArea> children}) {
    return DockingRow(children, id: id, weight: weight);
  }

  DockingColumn buildDockingColumn(
      {required dynamic id,
      required double? weight,
      required List<DockingArea> children}) {
    return DockingColumn(children, id: id, weight: weight);
  }

  /// Builds a [DockingTabs].
  DockingTabs buildDockingTabs(
      {required dynamic id,
      required double? weight,
      required bool maximized,
      required List<DockingItem> children}) {
    return DockingTabs(children, id: id, weight: weight, maximized: maximized);
  }
}

Example:

class _DockingExamplePageState extends State<DockingExamplePage>
    with LayoutParserMixin, AreaBuilderMixin {
  late DockingLayout _layout;

  void _test() {
    String layoutAsString = _layout.stringify(parser: this);
    print(layoutAsString);
    _layout.load(layout: layoutAsString, parser: this, builder: this);
  }

  @override
  DockingItem buildDockingItem(
      {required dynamic id, required double? weight, required bool maximized}) {
    // Check the id here to find out which and how to build the Widget.
    return DockingItem(
        name: id,
        maximized: maximized,
        weight: weight,
        widget: Text('restore test: $id'));
  }

...

caduandrade added a commit that referenced this issue Oct 20, 2023
@caduandrade caduandrade linked a pull request Oct 20, 2023 that will close this issue
caduandrade added a commit that referenced this issue Oct 20, 2023
* Adding layout indexes test. #1

* Refactor: creating a dart file to DockingAreaType and DropPosition

* Parser to String. #1

* Adding test. #1

* Fixing stringifyArea and adding test. #1

* Adding tests. #1

* Adding tests. #1

* Adding tests. #1

* Fixing stringify and adding test. #1

* Initial algorithm to convert from String to Docking Layout. #1

* Moving the attribute [id] from [DockingItem] to [DockingArea]. #1

* Building a DockingLayout from String. #1

* Adding findDockingArea method. #1

* Reusing parent _updateHierarchy method.

* Finishing the implementation with the stringify and load methods in the DockingLayout class. #1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants