Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f09cf7f
chore(deps): update kotlin jvm target and gradle wrapper version
tsinis Jan 2, 2026
64f198e
feat: enable impeller and update sdk version for world_flags package
tsinis Jan 3, 2026
f6f95c8
feat(ui)!: add clipped triangle painter and update flag properties
tsinis Jan 3, 2026
08b761a
feat(shader): add waved flag shader implementation
tsinis Jan 3, 2026
46eaf26
feat(ui): add shader options and delegate for flag rendering
tsinis Jan 3, 2026
b085416
feat: integrate flag shader delegate and remove shader options
tsinis Jan 3, 2026
4ecef84
feat(shader): add shader support to iso and country flag widgets
tsinis Jan 3, 2026
8492e82
feat(model): remove enabled option from waved flag shader
tsinis Jan 4, 2026
7a3a9c3
feat(model): remove shader delegate from basic flag implementation
tsinis Jan 4, 2026
7ea91eb
feat(shader): add waved flag shader delegate and update typedefs
tsinis Jan 4, 2026
259407f
refactor(ui): optimize shader painting and improve caching mechanism
tsinis Jan 4, 2026
a9b5c11
docs(ui): doc dispose method and improve documentation for painters
tsinis Jan 4, 2026
ff85805
fix(data)!: update alternate and disambiguate symbols for ars
tsinis Jan 5, 2026
0f2d825
refactor(shader): update shader references and improve resource manag…
tsinis Jan 6, 2026
f1b9571
feat(ui): add flag shader surface widget with customizable options
tsinis Jan 6, 2026
d6be045
refactor(shader): refactor waved flag shader with unrolled fbm functi…
tsinis Jan 7, 2026
62c2443
test(shader): add comprehensive tests for flag shader options and del…
tsinis Jan 7, 2026
dcf6df8
test(golden): add waved flag golden tests
tsinis Jan 7, 2026
f2f687a
test(ui): improve null safety and formatting in shader classes, fix c…
tsinis Jan 7, 2026
b747a46
style(test): improve formatting in waved flag shader delegate tests
tsinis Jan 7, 2026
0aa32de
chore(test): update golden test files for `world_flags` package
tsinis Jan 8, 2026
e4d9abb
fix(test): update alternate symbols in fiat currency to match spec
tsinis Jan 8, 2026
d21f812
style: improve formatting and clean up imports in various files
tsinis Jan 8, 2026
c242866
refactor: simplify wave direction equaluty in shader options and tests
tsinis Jan 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ final class FiatArs extends FiatCurrency {
decimalMark: ",",
thousandsSeparator: ".",
symbol: r"$",
alternateSymbols: const [r"$m/n", r"m$n"],
disambiguateSymbol: r"$m/n",
alternateSymbols: const [r"AR$"],
disambiguateSymbol: r"AR$",
htmlEntity: r"$",
codeNumeric: "032",
namesNative: const ["Argentine peso"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ void main() => group("$Currency", () {
currency.toString(short: false),
'FiatCurrency(code: "ARS", name: "Argentine Peso", '
r'decimalMark: ",", thousandsSeparator: ".", symbol: r"$", '
r'alternateSymbols: ["$m/n","m$n"], disambiguateSymbol: r"$m/n", '
r'alternateSymbols: ["AR$"], disambiguateSymbol: r"AR$", '
r'htmlEntity: r"$", codeNumeric: "032", '
'namesNative: ["Argentine peso"], priority: 100, '
'smallestDenomination: 1, subunit: "Centavo", subunitToUnit: 100, '
Expand Down
2 changes: 2 additions & 0 deletions packages/world_countries/example/macos/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>FLTEnableImpeller</key>
<true />
</dict>
</plist>
14 changes: 9 additions & 5 deletions packages/world_flags/example/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import java.util.concurrent.TimeUnit

plugins {
id("com.android.application")
id("kotlin-android")
Expand All @@ -15,10 +17,6 @@ android {
targetCompatibility = JavaVersion.VERSION_24
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_24.toString()
}

defaultConfig {
// Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.world_flags_example"
Expand All @@ -39,6 +37,12 @@ android {
}
}

kotlin {
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_24)
}
}

flutter {
source = "../.."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-all.zip
9 changes: 2 additions & 7 deletions packages/world_flags/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import "settings_dialog.dart";
void main() {
/// Provide flag decorations globally.
const extensions = [
FlagThemeData(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4)),
),
),
FlagThemeData(decoration: BoxDecoration(borderRadius: .all(.circular(4)))),
];

runApp(
Expand All @@ -33,8 +29,7 @@ class _MainState extends State<Main> {
// ignore: specify_nonobvious_property_types, a double as it's divided by 2.0.
static const _size = kMinInteractiveDimension / 2.0;
static const _items = <IsoTranslated, BasicFlag>{
...uniqueSimplifiedFlagsMap,
CountryGuf(): StarFlag(flagGufPropertiesAlt),
...smallSimplifiedFlagsMap,
FiatEur(): StarFlag(flagEurProperties),
...smallSimplifiedLanguageFlagsMap,
};
Expand Down
41 changes: 18 additions & 23 deletions packages/world_flags/example/lib/settings_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import "dart:async";

import "package:flutter/material.dart";
import "package:meta/meta.dart"; // ignore: depend_on_referenced_packages, example app.
import "package:world_flags/world_flags.dart";

class SettingsDialog extends StatefulWidget {
const SettingsDialog(this.aspectRatio, this.country, {super.key});

static void show(
@awaitNotRequired
static Future<void> show(
ValueNotifier<double?> aspectRatio,
BuildContext context,
WorldCountry country,
) => unawaited(
showDialog(
context: context,
builder: (_) => SettingsDialog(aspectRatio, country),
),
) => showDialog<void>(
context: context,
builder: (_) => SettingsDialog(aspectRatio, country),
);

final WorldCountry country;
Expand All @@ -25,7 +23,7 @@ class SettingsDialog extends StatefulWidget {
}

class _SettingsDialogState extends State<SettingsDialog> {
final _opacity = ValueNotifier<double>(1 / 2);
final _opacity = ValueNotifier<double>(1);

WorldCountry get _country => widget.country;

Expand Down Expand Up @@ -72,19 +70,15 @@ class _SettingsDialogState extends State<SettingsDialog> {
),
body: Center(
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitHeight,
image: NetworkImage(_country.flagPngUrl()),
),
),
child: AspectRatio(
aspectRatio:
ratio ??
_country.flagProperties?.aspectRatio ??
FlagConstants.defaultAspectRatio,
child: Opacity(opacity: opacityValue, child: flag),
),
decoration: opacityValue == 1
? const BoxDecoration()
: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitHeight,
image: NetworkImage(_country.flagPngUrl()),
),
),
child: Opacity(opacity: opacityValue, child: flag),
),
),
bottomNavigationBar: SliderTheme(
Expand All @@ -101,6 +95,7 @@ class _SettingsDialogState extends State<SettingsDialog> {
ratio ??
_country.flagProperties?.aspectRatio ??
FlagConstants.minAspectRatio,
secondaryTrackValue: _country.flagProperties?.aspectRatio,
onChanged: (newRatio) =>
widget.aspectRatio.value = newRatio,
min: FlagConstants.minAspectRatio,
Expand All @@ -120,7 +115,7 @@ class _SettingsDialogState extends State<SettingsDialog> {
),
),
),
child: CountryFlag.simplified(_country, aspectRatio: ratio),
child: FlagShaderSurface(_country, aspectRatio: ratio),
),
),
),
Expand Down
2 changes: 2 additions & 0 deletions packages/world_flags/example/macos/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>FLTEnableImpeller</key>
<true />
</dict>
</plist>
2 changes: 1 addition & 1 deletion packages/world_flags/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish_to: none
resolution: workspace

environment:
sdk: ^3.9.2
sdk: ^3.10.4

dependencies:
flutter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2385,7 +2385,7 @@ const flagLcaProperties = FlagProperties(
baseElementType: FlagElementsType.rectangle,
elementsProperties: [
ElementsProperties(
Color(0xff65cfff),
Color(0x0065cfff),
shape: Rectangle(),
offset: Offset(0, 4.5),
heightFactor: 0.82,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import "package:flutter/foundation.dart" show internal;

@internal
extension AspectRatioExtension<T extends double> on T? {
/// Calculated aspect ratio.
double? aspectRatio(double? width) =>
width == null || this == null ? null : width / (this ?? 1);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import "../../interfaces/decorated_flag_interface.dart";
import "aspect_ratio_extension.dart";

/// An extension on [DecoratedFlagInterface] that provides a method to calculate
/// the aspect ratio of the flag based on its width and height.
extension DecoratedFlagInterfaceExtension on DecoratedFlagInterface {
/// The calculated aspect ratio of the flag based on its width and height.
double? get calculatedAspectRatio =>
width == null || height == null ? null : (width ?? 1) / (height ?? 1);
double? get calculatedAspectRatio => height.aspectRatio(width);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import "package:flutter/widgets.dart";
import "package:sealed_countries/sealed_countries.dart" show IsoStandardized;

import "../../ui/effects/flag_shader_delegate.dart";
import "../../ui/flags/basic_flag.dart";
import "../../ui/iso_flag.dart";

Expand Down Expand Up @@ -36,20 +37,22 @@ extension IsoFlagExtension<T extends IsoStandardized, F extends BasicFlag>
BoxDecoration? decoration,
DecorationPosition? decorationPosition,
EdgeInsetsGeometry? padding,
FlagShaderDelegate? shader,
Widget? child,
Key? key,
}) => IsoFlag(
item ?? this.item,
map ?? this.map,
alternativeMap: alternativeMap ?? this.alternativeMap,
orElse: orElse ?? this.orElse,
height: height ?? this.height,
width: width ?? this.width,
aspectRatio: aspectRatio ?? this.aspectRatio,
decoration: decoration ?? this.decoration,
decorationPosition: decorationPosition ?? this.decorationPosition,
padding: padding ?? this.padding,
height: height ?? this.height,
item ?? this.item,
key: key ?? this.key,
map ?? this.map,
orElse: orElse ?? this.orElse,
padding: padding ?? this.padding,
width: width ?? this.width,
shader: shader ?? this.shader,
child: child ?? this.child,
);
}
11 changes: 11 additions & 0 deletions packages/world_flags/lib/src/model/typedefs.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import "package:flutter/widgets.dart";

import "../ui/effects/flag_shader_delegate.dart";
import "../ui/effects/flag_shader_options.dart";
import "elements/elements_properties.dart";
import "flag_properties.dart";

/// Signature for building shader delegate when no custom delegate is supplied.
typedef FlagShaderDelegateBuilder =
FlagShaderDelegate Function(
TickerProvider vsync,
FlagShaderOptions options,
FlagProperties properties,
);

/// A type definition for a list of [ElementsProperties].
typedef ElementsProps = List<ElementsProperties>;
Expand Down
7 changes: 4 additions & 3 deletions packages/world_flags/lib/src/ui/country_flag.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import "package:sealed_countries/sealed_countries.dart";

// ignore: avoid-importing-entrypoint-exports, only shows maps.
import "../../world_flags.dart"
show smallSimplifiedAlternativeFlagsMap, smallSimplifiedFlagsMap;
import "../../world_flags.dart" show smallSimplifiedFlagsMap;
import "flags/basic_flag.dart";
import "iso_flag.dart";

Expand Down Expand Up @@ -40,13 +39,14 @@ class CountryFlag extends IsoFlag<WorldCountry, BasicFlag> {
/// - [key]: The key for the widget.
const CountryFlag.simplified(
WorldCountry country, {
super.alternativeMap = smallSimplifiedAlternativeFlagsMap,
super.alternativeMap,
super.height,
super.width,
super.aspectRatio,
super.decoration,
super.decorationPosition,
super.padding,
super.shader,
super.orElse,
super.child,
super.key,
Expand Down Expand Up @@ -78,6 +78,7 @@ class CountryFlag extends IsoFlag<WorldCountry, BasicFlag> {
super.padding,
super.height,
super.width,
super.shader,
super.orElse,
super.child,
super.key,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import "dart:ui" show Canvas, Image, Size;

import "package:flutter/foundation.dart" show Listenable;

/// A delegate that knows how to post-process flag content with a shader.
///
/// Implementations can decide whether to apply a shader or bail out and let the
/// fallback painter run.
abstract class FlagShaderDelegate implements Listenable {
/// Creates a new instance of [FlagShaderDelegate].
const FlagShaderDelegate( // coverage:ignore-line
{
this.contentScale = 1, // Dart 3.8 formatting.
this.shouldClipContent = false,
});

/// Whether the painter should clip to the flag bounds before invoking the
/// shader.
///
/// Defaults to `false`, allowing shader effects to extend beyond the
/// rectangle.
final bool shouldClipContent;

/// Uniform scale factor to apply to the painted flag before handing it to the
/// shader.
///
/// Values below `1.0` shrink the base content to leave visual headroom for
/// shader-driven overflow. Defaults to `1.0` (no scaling).
final double contentScale;

/// Attempts to paint [image] with a shader.
///
/// Returns `true` when the shader path was taken. If `false` is returned, the
/// caller should paint the content normally.
bool paintWithShader(Canvas destination, Size size, {required Image image});

/// Releases any resources allocated by the delegate.
void dispose();
}
Loading