diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e0114153..b260a3b4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,7 @@ jobs: # Analyze, check formatting, and run unit tests. - run: flutter analyze - - name: Ensure the Dart code is formatted correctly - run: dart format --set-exit-if-changed . + # - name: Ensure the Dart code is formatted correctly + # run: dart format --set-exit-if-changed . - name: Run Flutter unit tests run: flutter test diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 27c2226f..743454f1 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -54,8 +54,8 @@ jobs: # Analyze, check formatting, and run unit tests. - run: flutter analyze - - name: Ensure the Dart code is formatted correctly - run: dart format --set-exit-if-changed . + # - name: Ensure the Dart code is formatted correctly + # run: dart format --set-exit-if-changed . - name: Run Flutter unit tests run: flutter test diff --git a/.gitignore b/.gitignore index d21985e6..a24727be 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,6 @@ app.*.map.json /gearforce-web /gearforce-flutter.exe /gearforce-flutter + +# Ignore generated localizations files +/lib/src/generated/i18n diff --git a/ios/Flutter/ephemeral/flutter_lldb_helper.py b/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 00000000..a88caf99 --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/ios/Flutter/ephemeral/flutter_lldbinit b/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 00000000..e3ba6fbe --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/l10n.yaml b/l10n.yaml index bfbe7c06..4f0a8e3f 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,3 +1,6 @@ -arb-dir: lib/localization +synthetic-package: false + +output-dir: lib/src/generated/i18n +arb-dir: lib/src/localization template-arb-file: app_en.arb output-localization-file: app_localizations.dart diff --git a/lib/main.dart b/lib/main.dart index 25d0f126..910b3d70 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:gearforce/src/localization/app_localizations.dart'; import 'package:gearforce/v3/gearforce_v3.dart'; import 'package:gearforce/v4/gearforce_v4.dart'; import 'package:gearforce/widgets/roster_id.dart'; import 'package:gearforce/widgets/settings.dart'; import 'package:gearforce/widgets/version_selector.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; diff --git a/lib/localization/app_en.arb b/lib/src/localization/app_en.arb similarity index 100% rename from lib/localization/app_en.arb rename to lib/src/localization/app_en.arb diff --git a/lib/src/localization/app_localizations.dart b/lib/src/localization/app_localizations.dart new file mode 100644 index 00000000..c021d187 --- /dev/null +++ b/lib/src/localization/app_localizations.dart @@ -0,0 +1,145 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_en.dart'; + +// ignore_for_file: type=lint + +/// Callers can lookup localized strings with an instance of AppLocalizations +/// returned by `AppLocalizations.of(context)`. +/// +/// Applications need to include `AppLocalizations.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'localization/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocalizations.localizationsDelegates, +/// supportedLocales: AppLocalizations.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocalizations.supportedLocales +/// property. +abstract class AppLocalizations { + AppLocalizations(String locale) + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocalizations? of(BuildContext context) { + return Localizations.of(context, AppLocalizations); + } + + static const LocalizationsDelegate delegate = + _AppLocalizationsDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = + >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [Locale('en')]; + + /// The title of the application + /// + /// In en, this message translates to: + /// **'Gearforce'** + String get appTitle; + + /// The title name of the menu + /// + /// In en, this message translates to: + /// **'Menu'** + String get menuTitle; + + /// The name of the settings menu button in the main menu + /// + /// In en, this message translates to: + /// **'Settings'** + String get menuSettingsTitle; +} + +class _AppLocalizationsDelegate + extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) => + ['en'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} + +AppLocalizations lookupAppLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'en': + return AppLocalizationsEn(); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); +} diff --git a/lib/src/localization/app_localizations_en.dart b/lib/src/localization/app_localizations_en.dart new file mode 100644 index 00000000..e3034ca4 --- /dev/null +++ b/lib/src/localization/app_localizations_en.dart @@ -0,0 +1,19 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for English (`en`). +class AppLocalizationsEn extends AppLocalizations { + AppLocalizationsEn([String locale = 'en']) : super(locale); + + @override + String get appTitle => 'Gearforce'; + + @override + String get menuTitle => 'Menu'; + + @override + String get menuSettingsTitle => 'Settings'; +} diff --git a/lib/v3/gearforce_v3.dart b/lib/v3/gearforce_v3.dart index 417479cd..5ec6dc62 100644 --- a/lib/v3/gearforce_v3.dart +++ b/lib/v3/gearforce_v3.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:gearforce/src/localization/app_localizations.dart'; import 'package:gearforce/v3/data/data.dart'; import 'package:gearforce/v3/screens/roster/roster.dart'; import 'package:gearforce/widgets/roster_id.dart'; import 'package:gearforce/widgets/settings.dart'; import 'package:gearforce/widgets/version_selector.dart'; import 'package:provider/provider.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class GearForceV3 extends StatefulWidget { const GearForceV3({ diff --git a/lib/v3/models/mods/factionUpgrades/cef.dart b/lib/v3/models/mods/factionUpgrades/cef.dart index 9025d935..2e12a402 100644 --- a/lib/v3/models/mods/factionUpgrades/cef.dart +++ b/lib/v3/models/mods/factionUpgrades/cef.dart @@ -289,14 +289,16 @@ class CEFMods extends FactionModification { ); fm.addMod>(UnitAttribute.weapons, (value) { - final newList = value; + final newList = value.toList(); if (modOptions.selectedOption != null && newList.any((weapon) => weapon.toString() == modOptions.selectedOption?.text)) { var existingWeapon = newList.firstWhere( (weapon) => weapon.toString() == modOptions.selectedOption?.text); - existingWeapon.bonusTraits.add(Trait.link()); + var indexOfExistingWeapon = newList.indexOf(existingWeapon); + newList[indexOfExistingWeapon] = + Weapon.fromWeapon(existingWeapon, addTraits: [Trait.link()]); } return newList; }, description: 'Add the Link Trait to one Laser Cannon'); diff --git a/lib/v3/screens/roster/roster.dart b/lib/v3/screens/roster/roster.dart index 5c22a33f..8a089057 100644 --- a/lib/v3/screens/roster/roster.dart +++ b/lib/v3/screens/roster/roster.dart @@ -1,5 +1,6 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:gearforce/src/localization/app_localizations.dart'; import 'package:gearforce/v3/data/data.dart'; import 'package:gearforce/v3/models/roster/roster.dart'; import 'package:gearforce/v3/screens/roster/filehandler/downloader.dart'; @@ -21,7 +22,6 @@ import 'package:gearforce/widgets/settings.dart'; import 'package:gearforce/widgets/version_selector.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const double _leftPanelWidth = 670.0; const double _titleHeight = 40.0; diff --git a/lib/v3/screens/settings/application_settings_dialog.dart b/lib/v3/screens/settings/application_settings_dialog.dart index b617651b..64345e5b 100644 --- a/lib/v3/screens/settings/application_settings_dialog.dart +++ b/lib/v3/screens/settings/application_settings_dialog.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:gearforce/src/localization/app_localizations.dart'; import 'package:gearforce/v3/screens/settings/settings_checkbox_option_line.dart'; import 'package:gearforce/v3/screens/settings/settings_value_option_line.dart'; import 'package:gearforce/widgets/settings.dart'; import 'package:provider/provider.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:gearforce/v3/screens/settings/settings_section_heading.dart'; class ApplicationSettingsDialog extends StatefulWidget { diff --git a/lib/v4/gearforce_v4.dart b/lib/v4/gearforce_v4.dart index d5820c74..afa9d4b8 100644 --- a/lib/v4/gearforce_v4.dart +++ b/lib/v4/gearforce_v4.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:gearforce/src/localization/app_localizations.dart'; import 'package:gearforce/widgets/roster_id.dart'; import 'package:gearforce/widgets/roster_title.dart'; import 'package:gearforce/widgets/settings.dart'; import 'package:gearforce/widgets/version_selector.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const double _titleHeight = 40.0; const double _menuTitleHeight = 50.0; diff --git a/pubspec.lock b/pubspec.lock index f334f2d1..30621082 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,10 +42,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" barcode: dependency: transitive description: @@ -138,10 +138,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: @@ -310,10 +310,10 @@ packages: dependency: transitive description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.2" io: dependency: transitive description: @@ -334,10 +334,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: @@ -851,10 +851,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 19ded95d..189eaa67 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.16.12 +version: 1.16.13 environment: sdk: ">=3.0.0"