diff --git a/app/assets/i18n/en-US.json b/app/assets/i18n/en-US.json index 4a369ddd..f362d3bd 100644 --- a/app/assets/i18n/en-US.json +++ b/app/assets/i18n/en-US.json @@ -2,5 +2,10 @@ "main_page.side_bar.universe_chat": "Universe Chat", "main_page.side_bar.home": "Home", "main_page.side_bar.library": "Library", - "main_page.size_bar.multiplayer": "Multiplayer" + "main_page.side_bar.multiplayer": "Multiplayer", + "main_page.side_bar.create_collection": "Create Collection", + "main_page.side_bar.explore": "Explore Collections", + "main_page.side_bar.manage_downloads": "Manage Downloads", + "main_page.side_bar.manage_accounts": "Manage Accounts", + "dialog.setup.01.title": "Welcome" } \ No newline at end of file diff --git a/app/assets/i18n/zh-TW.json b/app/assets/i18n/zh-TW.json index 338c6612..34b5d5d8 100644 --- a/app/assets/i18n/zh-TW.json +++ b/app/assets/i18n/zh-TW.json @@ -6,5 +6,12 @@ "main_page.side_bar.create_collection": "建立收藏", "main_page.side_bar.explore": "探索收藏", "main_page.side_bar.manage_downloads": "管理下載", - "main_page.side_bar.manage_accounts": "管理帳號" + "main_page.side_bar.manage_accounts": "管理帳號", + "dialog.setup.01.title": "歡迎使用", + "dialog.setup.01.description": "歡迎你來到 Era Connect!\n開始使用啟動器之前,讓我們協助你進行快速設定,就可以盡情地暢玩遊戲啦。", + "dialog.setup.01.content.title": "匯入或是新建設定", + "dialog.setup.01.content.description": "你可以重新開始設定啟動器或是匯入先前的設定", + "dialog.setup.01.content.tab.title": "選擇方式", + "dialog.setup.01.content.tabs.empty.title": "從頭開始", + "dialog.setup.01.content.tabs.import.title": "匯入設定" } \ No newline at end of file diff --git a/app/lib/dialog/setup_dialog.dart b/app/lib/dialog/setup_dialog.dart new file mode 100644 index 00000000..e247dfa6 --- /dev/null +++ b/app/lib/dialog/setup_dialog.dart @@ -0,0 +1,57 @@ +import 'package:era_connect_i18n/era_connect_i18n.dart'; +import 'package:era_connect_ui/era_connect_ui.dart'; +import 'package:flutter/material.dart'; + +class SetupDialog extends StatelessWidget { + const SetupDialog({super.key}); + + @override + Widget build(BuildContext context) { + return InteractiveDialog( + title: context.i18n['dialog.setup.01.title'], + description: context.i18n['dialog.setup.01.description'], + logoBoxText: '01', + body: Padding( + padding: + const EdgeInsets.only(top: 45, bottom: 35, left: 45, right: 45), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.i18n['dialog.setup.01.content.title'], + style: TextStyle( + color: context.theme.textColor, + fontSize: 40, + fontWeight: FontWeight.w700, + ), + ), + Text( + context.i18n['dialog.setup.01.content.description'], + style: TextStyle( + color: context.theme.tertiaryTextColor, fontSize: 15), + ), + const SizedBox(height: 25), + DialogRectangleTab( + title: '選擇方式', + tabs: [ + TabItem( + title: + context.i18n['dialog.setup.01.content.tabs.empty.title'], + icon: 'deployed_code', + content: + const Text('這是從頭開始的頁面', style: TextStyle(fontSize: 30)), + ), + TabItem( + title: context + .i18n['dialog.setup.01.content.tabs.import.title'], + icon: 'deployed_code_update', + content: const Text('這是匯入設定的頁面', + style: TextStyle(fontSize: 50))), + ], + ) + ], + ), + ), + ); + } +} diff --git a/app/lib/main.dart b/app/lib/main.dart index 50d184a2..e7e39010 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -1,6 +1,7 @@ import 'package:era_connect_i18n/era_connect_i18n.dart'; import 'package:era_connect_ui/era_connect_ui.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; // import 'ffi.dart' show api; import 'pages/main_page.dart'; @@ -96,7 +97,7 @@ class _AppHomeState extends State<_AppHome> { final i18n = context.i18n; i18n.setLocale(I18nLocale.getFromSystemLocale( WidgetsBinding.instance.platformDispatcher)); - await i18n.load(); + await i18n.load(rootBundle); setState(() { isLoaded = true; }); diff --git a/app/lib/pages/main_page.dart b/app/lib/pages/main_page.dart index 58598ebd..3c11792c 100644 --- a/app/lib/pages/main_page.dart +++ b/app/lib/pages/main_page.dart @@ -1,3 +1,4 @@ +import 'package:era_connect/dialog/setup_dialog.dart'; import 'package:era_connect_i18n/era_connect_i18n.dart'; import 'package:era_connect_ui/era_connect_ui.dart'; import 'package:flutter/material.dart'; @@ -19,13 +20,7 @@ class _MainPageState extends State { showEraDialog( context: context, barrierDismissible: true, - dialog: const InteractiveDialog( - title: '歡迎使用', - description: - '歡迎你來到 Era Connect!\n開始使用啟動器之前,讓我們協助你進行快速設定,就可以盡情地暢玩遊戲啦。', - logoBoxText: '01', - child: Placeholder(), - ), + dialog: const SetupDialog(), ); } }); diff --git a/packages/era_connect_i18n/lib/i18n_manager.dart b/packages/era_connect_i18n/lib/i18n_manager.dart index 227f1ebf..caeadc85 100644 --- a/packages/era_connect_i18n/lib/i18n_manager.dart +++ b/packages/era_connect_i18n/lib/i18n_manager.dart @@ -37,7 +37,7 @@ class I18nManager extends ChangeNotifier implements ReassembleHandler { /// en-US.json /// zh-TW.json /// ``` - Future load() async { + Future load(AssetBundle rootBundle) async { _data.clear(); for (final locale in I18nLocale.values) { @@ -56,7 +56,7 @@ class I18nManager extends ChangeNotifier implements ReassembleHandler { @override void reassemble() { - load(); + load(rootBundle); } } diff --git a/packages/era_connect_i18n/test/i18n_locale_test.dart b/packages/era_connect_i18n/test/i18n_locale_test.dart index fac22d68..062cc043 100644 --- a/packages/era_connect_i18n/test/i18n_locale_test.dart +++ b/packages/era_connect_i18n/test/i18n_locale_test.dart @@ -10,8 +10,6 @@ import 'i18n_locale_test.mocks.dart'; @GenerateMocks([ui.PlatformDispatcher]) void main() { group('I18nLocale', () { - setUp(() => WidgetsFlutterBinding.ensureInitialized()); - test( 'getFromSystemLocale returns americanEnglish when system locale is not supported', () { diff --git a/packages/era_connect_i18n/test/i18n_manager_test.dart b/packages/era_connect_i18n/test/i18n_manager_test.dart new file mode 100644 index 00000000..4cfe892e --- /dev/null +++ b/packages/era_connect_i18n/test/i18n_manager_test.dart @@ -0,0 +1,129 @@ +import 'package:era_connect_i18n/i18n_locale.dart'; +import 'package:era_connect_i18n/i18n_manager.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; + +import 'i18n_manager_test.mocks.dart'; + +@GenerateNiceMocks( + [MockSpec(onMissingStub: OnMissingStub.throwException)]) +void main() { + group('I18nManager', () { + test('loads translations from JSON files', () async { + // Arrange + final i18nManager = I18nManager( + path: 'assets/i18n', + defaultLocale: I18nLocale.americanEnglish, + ); + final mockAssetBundle = MockAssetBundle(); + const jsonString = '{"hello": "Hello", "world": "World"}'; + + when(mockAssetBundle.loadString('assets/i18n/en-US.json')) + .thenAnswer((_) => Future.value(jsonString)); + when(mockAssetBundle.loadString('assets/i18n/zh-TW.json')) + .thenAnswer((_) => Future.value('{}')); + + // Act + await i18nManager.load(mockAssetBundle); + + // Assert + expect(i18nManager.defaultLocale, equals(I18nLocale.americanEnglish)); + expect(i18nManager['hello'], equals('Hello')); + expect(i18nManager['world'], equals('World')); + }); + + test('returns the key if no translation is found', () async { + // Arrange + final i18nManager = I18nManager( + path: 'assets/i18n', + defaultLocale: I18nLocale.americanEnglish, + ); + + final mockAssetBundle = MockAssetBundle(); + when(mockAssetBundle.loadString('assets/i18n/en-US.json')) + .thenAnswer((_) => Future.value('{}')); + when(mockAssetBundle.loadString('assets/i18n/zh-TW.json')) + .thenAnswer((_) => Future.value('{}')); + + // Act + await i18nManager.load(mockAssetBundle); + + // Assert + expect(i18nManager['missing_key'], equals('missing_key')); + }); + + test('sets the current locale', () { + // Arrange + final i18nManager = I18nManager( + path: 'assets/i18n', + defaultLocale: I18nLocale.americanEnglish, + ); + + // Act + i18nManager.setLocale(I18nLocale.traditionalChineseTW); + + // Assert + expect(i18nManager.locale, equals(I18nLocale.traditionalChineseTW)); + }); + + test('notifies listeners when the locale is changed', () { + // Arrange + final i18nManager = I18nManager( + path: 'assets/i18n', + defaultLocale: I18nLocale.americanEnglish, + ); + var notified = false; + i18nManager.addListener(() { + notified = true; + }); + + // Act + i18nManager.setLocale(I18nLocale.traditionalChineseTW); + + // Assert + expect(notified, isTrue); + }); + + testWidgets('get i18n manager from build context', (tester) async { + // Arrange + final i18nManager = I18nManager( + path: 'assets/i18n', + defaultLocale: I18nLocale.americanEnglish, + ); + final mockAssetBundle = MockAssetBundle(); + const jsonString = '{"hello": "Hello", "world": "World"}'; + + when(mockAssetBundle.loadString('assets/i18n/en-US.json')) + .thenAnswer((_) => Future.value(jsonString)); + when(mockAssetBundle.loadString('assets/i18n/zh-TW.json')) + .thenAnswer((_) => Future.value('{}')); + + // Act + await i18nManager.load(mockAssetBundle); + await tester.pumpWidget( + MaterialApp( + home: ChangeNotifierProvider( + create: (context) => i18nManager, + child: Builder( + builder: (context) { + final i18nManager = context.i18n; + return Column( + children: [ + Text(i18nManager['hello']), + Text(i18nManager['world']), + ], + ); + }, + ), + )), + ); + + // Assert + expect(find.text('Hello'), findsOneWidget); + expect(find.text('World'), findsOneWidget); + }); + }); +} diff --git a/packages/era_connect_i18n/test/i18n_manager_test.mocks.dart b/packages/era_connect_i18n/test/i18n_manager_test.mocks.dart new file mode 100644 index 00000000..f17f6034 --- /dev/null +++ b/packages/era_connect_i18n/test/i18n_manager_test.mocks.dart @@ -0,0 +1,181 @@ +// Mocks generated by Mockito 5.4.2 from annotations +// in era_connect_i18n/test/i18n_manager_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; +import 'dart:typed_data' as _i5; +import 'dart:ui' as _i2; + +import 'package:flutter/src/services/asset_bundle.dart' as _i4; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i6; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeImmutableBuffer_0 extends _i1.SmartFake + implements _i2.ImmutableBuffer { + _FakeImmutableBuffer_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeFuture_1 extends _i1.SmartFake implements _i3.Future { + _FakeFuture_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [AssetBundle]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockAssetBundle extends _i1.Mock implements _i4.AssetBundle { + MockAssetBundle() { + _i1.throwOnMissingStub(this); + } + + @override + _i3.Future<_i5.ByteData> load(String? key) => (super.noSuchMethod( + Invocation.method( + #load, + [key], + ), + returnValue: _i3.Future<_i5.ByteData>.value(_i5.ByteData(0)), + ) as _i3.Future<_i5.ByteData>); + @override + _i3.Future<_i2.ImmutableBuffer> loadBuffer(String? key) => + (super.noSuchMethod( + Invocation.method( + #loadBuffer, + [key], + ), + returnValue: + _i3.Future<_i2.ImmutableBuffer>.value(_FakeImmutableBuffer_0( + this, + Invocation.method( + #loadBuffer, + [key], + ), + )), + ) as _i3.Future<_i2.ImmutableBuffer>); + @override + _i3.Future loadString( + String? key, { + bool? cache = true, + }) => + (super.noSuchMethod( + Invocation.method( + #loadString, + [key], + {#cache: cache}, + ), + returnValue: _i3.Future.value(''), + ) as _i3.Future); + @override + _i3.Future loadStructuredData( + String? key, + _i3.Future Function(String)? parser, + ) => + (super.noSuchMethod( + Invocation.method( + #loadStructuredData, + [ + key, + parser, + ], + ), + returnValue: _i6.ifNotNull( + _i6.dummyValueOrNull( + this, + Invocation.method( + #loadStructuredData, + [ + key, + parser, + ], + ), + ), + (T v) => _i3.Future.value(v), + ) ?? + _FakeFuture_1( + this, + Invocation.method( + #loadStructuredData, + [ + key, + parser, + ], + ), + ), + ) as _i3.Future); + @override + _i3.Future loadStructuredBinaryData( + String? key, + _i3.FutureOr Function(_i5.ByteData)? parser, + ) => + (super.noSuchMethod( + Invocation.method( + #loadStructuredBinaryData, + [ + key, + parser, + ], + ), + returnValue: _i6.ifNotNull( + _i6.dummyValueOrNull( + this, + Invocation.method( + #loadStructuredBinaryData, + [ + key, + parser, + ], + ), + ), + (T v) => _i3.Future.value(v), + ) ?? + _FakeFuture_1( + this, + Invocation.method( + #loadStructuredBinaryData, + [ + key, + parser, + ], + ), + ), + ) as _i3.Future); + @override + void evict(String? key) => super.noSuchMethod( + Invocation.method( + #evict, + [key], + ), + returnValueForMissingStub: null, + ); + @override + void clear() => super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValueForMissingStub: null, + ); +} diff --git a/packages/era_connect_ui/icons/deployed_code.svg b/packages/era_connect_ui/icons/deployed_code.svg new file mode 100644 index 00000000..18ad4388 --- /dev/null +++ b/packages/era_connect_ui/icons/deployed_code.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/era_connect_ui/icons/deployed_code_update.svg b/packages/era_connect_ui/icons/deployed_code_update.svg new file mode 100644 index 00000000..4ed26443 --- /dev/null +++ b/packages/era_connect_ui/icons/deployed_code_update.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/era_connect_ui/lib/components/dialog/dialog_rectangle_tab.dart b/packages/era_connect_ui/lib/components/dialog/dialog_rectangle_tab.dart new file mode 100644 index 00000000..2a23c0d6 --- /dev/null +++ b/packages/era_connect_ui/lib/components/dialog/dialog_rectangle_tab.dart @@ -0,0 +1,128 @@ +import 'package:era_connect_ui/era_connect_ui.dart'; +import 'package:flutter/material.dart'; + +class TabItem { + final String title; + final String icon; + final Widget content; + + const TabItem( + {required this.title, required this.icon, required this.content}); +} + +class DialogRectangleTab extends StatefulWidget { + final String title; + final List tabs; + const DialogRectangleTab({super.key, required this.title, required this.tabs}) + : assert(tabs.length > 1); + + @override + State createState() => _DialogRectangleTabState(); +} + +class _DialogRectangleTabState extends State { + int _currentPage = 0; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.title, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 10), + Wrap( + spacing: 15, + children: widget.tabs.map((e) => _buildTab(e)).toList()), + const SizedBox(height: 30), + _buildContent() + ], + ); + } + + Widget _buildContent() { + return AnimatedSwitcher( + transitionBuilder: (child, animation) { + return FadeTransition( + opacity: animation, + child: SizeTransition( + sizeFactor: animation, + child: child, + ), + ); + }, + switchInCurve: Curves.easeInOut, + switchOutCurve: Curves.easeInOut, + duration: const Duration(milliseconds: 150), + child: Container( + key: ValueKey(_currentPage), + child: widget.tabs[_currentPage].content)); + } + + Widget _buildTab(TabItem e) { + return AnimatedSwitcher( + transitionBuilder: (child, animation) { + return FadeTransition(opacity: animation, child: child); + }, + duration: const Duration(milliseconds: 150), + child: _TabItemWidget( + key: ValueKey(_currentPage), + title: e.title, + icon: e.icon, + isSelected: widget.tabs.indexOf(e) == _currentPage, + onTap: () async { + int page = widget.tabs.indexOf(e); + setState(() { + _currentPage = page; + }); + }, + ), + ); + } +} + +class _TabItemWidget extends StatelessWidget { + final String title; + final String icon; + final bool isSelected; + final VoidCallback onTap; + + const _TabItemWidget( + {super.key, + required this.title, + required this.icon, + required this.isSelected, + required this.onTap}); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Container( + width: 200, + height: 150, + decoration: BoxDecoration( + color: context.theme.backgroundColor, + borderRadius: BorderRadius.circular(15), + border: isSelected + ? Border.all(color: context.theme.accentColor, width: 3) + : null, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + EraIcon(name: icon, size: 50), + const SizedBox(height: 10), + Text( + title, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ) + ], + ), + ), + ); + } +} diff --git a/packages/era_connect_ui/lib/components/dialog/interactive_dialog.dart b/packages/era_connect_ui/lib/components/dialog/interactive_dialog.dart index fb518f33..3efc4f8c 100644 --- a/packages/era_connect_ui/lib/components/dialog/interactive_dialog.dart +++ b/packages/era_connect_ui/lib/components/dialog/interactive_dialog.dart @@ -13,32 +13,36 @@ class InteractiveDialog extends StatelessWidget { final bool hasBrandText; /// The content of the dialog (right side). - final Widget child; + final Widget body; + + final Widget? statusBox; const InteractiveDialog( {super.key, required this.title, required this.description, required this.logoBoxText, - required this.child, - this.hasBrandText = true}); + this.hasBrandText = true, + required this.body, + this.statusBox}); @override Widget build(BuildContext context) { return Dialog( - insetPadding: const EdgeInsets.symmetric(horizontal: 85, vertical: 45), - child: Container( - height: 900, - width: 1600, - decoration: BoxDecoration( + insetPadding: + const EdgeInsets.only(top: 75, bottom: 35, left: 85, right: 85), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: Container( + height: 900, + width: 1600, color: context.theme.backgroundColor, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - children: [ - Expanded(flex: 3, child: _buildLeftArea(context)), - Expanded(flex: 7, child: _buildRightArea(context)), - ], + child: Row( + children: [ + Expanded(flex: 3, child: _buildLeftArea(context)), + Expanded(flex: 7, child: _buildRightArea(context)), + ], + ), ), ), ); @@ -50,37 +54,32 @@ class InteractiveDialog extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - runSpacing: 15, + Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildLogoBox(context), + const SizedBox(height: 15), Text( title, style: TextStyle( fontSize: 60, color: context.theme.textColor, - fontWeight: FontWeight.w900), + fontWeight: FontWeight.w700), ), Text( description, style: TextStyle( - fontSize: 17, - color: context.theme.tertiaryTextColor, - fontWeight: FontWeight.w500), + fontSize: 17, color: context.theme.tertiaryTextColor), ), ], ), - const Placeholder(), + if (statusBox != null) statusBox!, ], )); } Container _buildRightArea(BuildContext context) { - return Container( - color: context.theme.deepBackgroundColor, - child: child, - ); + return Container(color: context.theme.deepBackgroundColor, child: body); } Container _buildLogoBox(BuildContext context) { @@ -121,7 +120,6 @@ class InteractiveDialog extends StatelessWidget { style: TextStyle( fontFamily: 'Geo', fontSize: 25, - fontWeight: FontWeight.w500, color: context.theme.accentColor)), ), ], diff --git a/packages/era_connect_ui/lib/components/dialog/lib.dart b/packages/era_connect_ui/lib/components/dialog/lib.dart index 9e3d641c..4975cb67 100644 --- a/packages/era_connect_ui/lib/components/dialog/lib.dart +++ b/packages/era_connect_ui/lib/components/dialog/lib.dart @@ -1,2 +1,3 @@ export 'interactive_dialog.dart'; -export 'dialog.dart'; \ No newline at end of file +export 'dialog.dart'; +export 'dialog_rectangle_tab.dart'; diff --git a/packages/era_connect_ui/lib/components/misc/era_icon.dart b/packages/era_connect_ui/lib/components/misc/era_icon.dart new file mode 100644 index 00000000..00063a72 --- /dev/null +++ b/packages/era_connect_ui/lib/components/misc/era_icon.dart @@ -0,0 +1,15 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class EraIcon extends StatelessWidget { + final String name; + final double? size; + + const EraIcon({super.key, required this.name, this.size}); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset('icons/$name.svg', + width: size, height: size, package: 'era_connect_ui'); + } +} diff --git a/packages/era_connect_ui/lib/components/misc/era_logo.dart b/packages/era_connect_ui/lib/components/misc/era_logo.dart index afdd7d88..6a9bfac6 100644 --- a/packages/era_connect_ui/lib/components/misc/era_logo.dart +++ b/packages/era_connect_ui/lib/components/misc/era_logo.dart @@ -1,17 +1,5 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_svg/flutter_svg.dart'; +import 'package:era_connect_ui/components/lib.dart'; -class EraLogo extends StatelessWidget { - final double? size; - const EraLogo({super.key, this.size}); - - @override - Widget build(BuildContext context) { - return SvgPicture.asset( - 'icons/era_connect_logo.svg', - package: 'era_connect_ui', - height: size, - width: size, - ); - } +class EraLogo extends EraIcon { + const EraLogo({super.key, super.size}) : super(name: 'era_connect_logo'); } diff --git a/packages/era_connect_ui/lib/components/misc/lib.dart b/packages/era_connect_ui/lib/components/misc/lib.dart index 9d57adec..5ac58a3f 100644 --- a/packages/era_connect_ui/lib/components/misc/lib.dart +++ b/packages/era_connect_ui/lib/components/misc/lib.dart @@ -1,4 +1,5 @@ export 'era_divider.dart'; export 'era_tooltip.dart'; export 'era_logo.dart'; -export 'era_brand_text.dart'; \ No newline at end of file +export 'era_brand_text.dart'; +export 'era_icon.dart'; \ No newline at end of file diff --git a/packages/era_connect_ui/lib/components/title_bar/era_title_bar_action.dart b/packages/era_connect_ui/lib/components/title_bar/era_title_bar_action.dart index 3e50dfe1..8c558a60 100644 --- a/packages/era_connect_ui/lib/components/title_bar/era_title_bar_action.dart +++ b/packages/era_connect_ui/lib/components/title_bar/era_title_bar_action.dart @@ -1,5 +1,5 @@ +import 'package:era_connect_ui/components/lib.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:window_manager/window_manager.dart'; class EraTitleBarAction { @@ -11,8 +11,7 @@ class EraTitleBarAction { static Widget minimize() { return IconButton( - icon: SvgPicture.asset('icons/drag_handle.svg', - package: 'era_connect_ui', height: 20), + icon: const EraIcon(name: 'drag_handle', size: 20), style: _style, onPressed: () { windowManager.minimize(); @@ -22,8 +21,7 @@ class EraTitleBarAction { static Widget maximize() { return IconButton( - icon: SvgPicture.asset('icons/thumbnail_bar.svg', - package: 'era_connect_ui', height: 20), + icon: const EraIcon(name: 'thumbnail_bar', size: 20), style: _style, onPressed: () async { final isMaximized = await windowManager.isMaximized(); @@ -38,8 +36,7 @@ class EraTitleBarAction { static Widget close() { return IconButton( - icon: SvgPicture.asset('icons/close.svg', - package: 'era_connect_ui', height: 20), + icon: const EraIcon(name: 'close', size: 20), hoverColor: const Color(0xffff0000), style: _style, onPressed: () {