Description
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):
- supports
/assets/{flavor}/**
format - 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