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

[FR]: Flavors API needs improvements... #624

Open
2 tasks done
MatrixDev opened this issue Jan 3, 2025 · 1 comment
Open
2 tasks done

[FR]: Flavors API needs improvements... #624

MatrixDev opened this issue Jan 3, 2025 · 1 comment
Labels
enhancement New feature or request

Comments

@MatrixDev
Copy link

MatrixDev commented Jan 3, 2025

Is there an existing issue for this?

  • I have searched the existing issues

Describe the problem

Common pattern for whitelabel solutions is to have different flavors folders per customer:

assets/
  customer1/
    logo.png
  customer2/
    logo.png

And after that you just get resource as:

"assets/${appFlavor}/logo.png"

Sadly, this is basically not possible to do with flutterGen. There is no way to "inject" flavor:

Assets.getFlavor(appFlavor).logo

You cannot switch-case root flavor directory because types are different $AssetsCustomer1Gen vs $AssetsCustomer2Gen:

??? getFlavorAssets() {
  return switch (appFlavor) {
    case "customer1" => Assets.customer1,
    case "customer2" => Assets.customer2,
    _ => throw "error",
  };
}

Basically the only solution I can see at this moment is to switch case for each "flavored" resource:

AssetGenImage getLogo() {
  return switch (appFlavor) {
    case "customer1" => Assets.customer1.logo,
    case "customer2" => Assets.customer2.logo,
    _ => throw "error",
  };
}

But this get very tedious when many assets are present and somewhat removes the point of FlutterGen except compilte-time safety.

PS:
Each asset (even when it is present in multiple flavors) has flavors field which always contains a single flavor at best. What is even the point of this field?

Describe the solution

I understand that FlutterGen doesn't want to impose its own folder structure requirements while flutter provides full customizability but without it such cases might not be possible to solve in a reasonable way.

What I suggest is to add additional layer of code generation. So it will generate all assets as it currently does (eg. basically mirroring tree structure of original folders) but also (can be configurable):

  1. supports /assets/{flavor}/** format
  2. provides additional "flavored" tree

Lets say we have following assets:

assets/
  customer1/
    images/
      logo.png
  customer2/
    images/
      logo.png
      exclusive.png

FlutterGen can generate something like:

class Assets {
  Assets._();

  // as-is assets tree (current implementation)
  static const $AssetsCustomer1Gen customer1 = $AssetsCustomer1Gen();
  static const $AssetsCustomer1Gen customer2 = $AssetsCustomer1Gen();

  // newly added stuff
  static const Map<String, $AssetsGenFlavor> rootFlavors = {
    "customer1": $AssetsGenFlavorCustomer1(),
    "customer2": $AssetsGenFlavorCustomer2(),
  };
}

// "root" flavor container

abstract class $AssetsGenFlavor {
  const $AssetsGenFlavor();

  $AssetsImagesGenFlavor get images;
}

class $AssetsGenFlavorCustomer1 extends $AssetsGenFlavor {
  const $AssetsGenFlavorCustomer1();
  
  @override
  $AssetsImagesGenFlavorCustomer1 get images => const $AssetsImagesGenFlavorCustomer1();
}

class $AssetsGenFlavorCustomer2 extends $AssetsGenFlavor {
  const $AssetsGenFlavorCustomer2();
  
  @override
  $AssetsImagesGenFlavorCustomer2 get images => const $AssetsImagesGenFlavorCustomer2();
}

// flavored images

abstract class $AssetsImagesGenFlavor {
  const $AssetsImagesGenFlavor();

  // present for all flavors, non-nullable
  AssetGenImage get logo;

  // present for some flavors, nullable
  AssetGenImage? get exclusive;
}

class $AssetsImagesGenFlavorCustomer1 extends $AssetsImagesGenFlavor {
  const $AssetsImagesGenFlavorCustomer1();

  @override
  AssetGenImage get logo => const AssetGenImage(
        'assets/customer1/images/logo.png',
        flavors: {'customer1', 'customer2'},
      );

  @override
  AssetGenImage? get exclusive => null;
}

class $AssetsImagesGenFlavorCustomer2 extends $AssetsImagesGenFlavor {
  const $AssetsImagesGenFlavorCustomer2();

  @override
  AssetGenImage get logo => const AssetGenImage(
        'assets/customer2/images/logo.png',
        flavors: {'customer1', 'customer2'},
      );

  @override
  AssetGenImage? get exclusive => const AssetGenImage(
        'assets/customer2/images/exclusive.png',
        flavors: {'customer2'},
      );
}

Personally, I don't see any point in flavors field but in case there are any - this solution fits it.

Additional context

It would also be greate if flavors can override common resources but it is no a part of current task.

Code of Conduct

  • I agree to follow this project's Code of Conduct
@MatrixDev MatrixDev added the enhancement New feature or request label Jan 3, 2025
@MatrixDev MatrixDev changed the title [FR]: Flavors API is not good and should be redesigned... [FR]: Flavors API needs improvements... Jan 3, 2025
@AlexV525
Copy link
Member

Each asset (even when it is present in multiple flavors) has flavors field which always contains a single flavor at best. What is even the point of this field?

The structure follows the conditionally bundling assets 1 of Flutter to solve the previous blocking issue 2.

Flavors require a solid decision. There are several things I can imagine to implement the flavor feature:

  1. Recognize flavors. There are a couple of ways:
  • Manually specify flavors through configuration, such as flutter_gen > assets > flavors. Users need to define each flavor with a corresponding path (say assets/demo for "demo", assets/app for "app").
  • Read all flavors from native (build.gradle, Runner.xcworkspace, etc). This would be hard to implement since the format is variant.
  1. Make sure all flavored assets exist. For example, if assets/demo/1.jpg exists, then assets/app/2.jpg must exist. But that does not sound like a production solution since people should have a base flavor and other flavors are only subsets.
  2. Make sure the flavored assets can be only accessed with the corresponding flavor. For example, you can only access assets/demo/2.jpg when the flavor is demo rather than app. Flutter already does its part, but with the gen library, I don't think we can provide good access to such assets.

Footnotes

  1. https://docs.flutter.dev/deployment/flavors#conditionally-bundling-assets-based-on-flavor

  2. https://github.com/FlutterGen/flutter_gen/issues/494

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

No branches or pull requests

2 participants