diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml index 516b643830..ade275c2ca 100644 --- a/.github/workflows/flatpak.yml +++ b/.github/workflows/flatpak.yml @@ -86,7 +86,7 @@ jobs: draft: false prerelease: false title: "Latest Release" - automatic_release_tag: "v5.0.162" + automatic_release_tag: "v5.0.163" files: | ${{ github.workspace }}/artifacts/Invoice-Ninja-Archive ${{ github.workspace }}/artifacts/Invoice-Ninja-Hash diff --git a/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml b/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml index 69f7e641fb..9cac3b21ec 100644 --- a/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml +++ b/flatpak/com.invoiceninja.InvoiceNinja.metainfo.xml @@ -50,6 +50,7 @@ + diff --git a/lib/constants.dart b/lib/constants.dart index 2b01957c4b..a9f1df8996 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -6,7 +6,7 @@ class Constants { } // TODO remove version once #46609 is fixed -const String kClientVersion = '5.0.162'; +const String kClientVersion = '5.0.163'; const String kMinServerVersion = '5.0.4'; const String kAppName = 'Invoice Ninja'; @@ -119,6 +119,7 @@ const String kSharedPrefToken = 'checksum'; const String kSharedPrefWidth = 'width'; const String kSharedPrefHeight = 'height'; const String kSharedPrefMaximized = 'maximized'; +const String kSharedPrefHostOverride = 'host_override'; const String kProductProPlanMonth = 'pro_plan'; const String kProductEnterprisePlanMonth_2 = 'enterprise_plan'; diff --git a/lib/main.dart b/lib/main.dart index 2265bd1910..1c66ef0824 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -99,7 +99,25 @@ emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- '''; +// https://www.reddit.com/r/flutterhelp/comments/1cnb3q0/certificate_verify_failed_whats_the_right/ +class MyHttpOverrides extends HttpOverrides { + MyHttpOverrides(this.host); + final String host; + + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = (X509Certificate cert, String host, int port) { + return this.host == host; + }; + } +} + void main({bool isTesting = false}) async { + final prefs = await SharedPreferences.getInstance(); + HttpOverrides.global = + MyHttpOverrides(prefs.getString(kSharedPrefHostOverride) ?? ''); + WidgetsFlutterBinding.ensureInitialized(); _registerErrorHandlers(); @@ -115,8 +133,6 @@ void main({bool isTesting = false}) async { // Ignore CERT_ALREADY_IN_HASH_TABLE } - final prefs = await SharedPreferences.getInstance(); - if (isDesktopOS()) { await windowManager.ensureInitialized(); diff --git a/lib/ui/auth/login_view.dart b/lib/ui/auth/login_view.dart index b720a25935..af8ca3fdae 100644 --- a/lib/ui/auth/login_view.dart +++ b/lib/ui/auth/login_view.dart @@ -11,6 +11,7 @@ import 'package:invoiceninja_flutter/ui/app/sms_verification.dart'; // Package imports: import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:rounded_loading_button/rounded_loading_button.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -58,6 +59,7 @@ class _LoginState extends State { final _secretController = TextEditingController(); final _oneTimePasswordController = TextEditingController(); final _tokenController = TextEditingController(); + final _hostOverrideController = TextEditingController(); final _buttonController = RoundedLoadingButtonController(); @@ -76,6 +78,7 @@ class _LoginState extends State { bool _tokenLogin = false; bool _isSelfHosted = false; bool _createAccount = false; + bool _showSettings = false; bool _recoverPassword = false; bool _disable2FA = false; @@ -118,6 +121,11 @@ class _LoginState extends State { if (_urlController.text.isEmpty) { _urlController.text = widget.viewModel.authState.url; } + + SharedPreferences.getInstance().then((value) { + _hostOverrideController.text = + value.getString(kSharedPrefHostOverride) ?? ''; + }); } @override @@ -130,6 +138,7 @@ class _LoginState extends State { _secretController.dispose(); _oneTimePasswordController.dispose(); _tokenController.dispose(); + _hostOverrideController.dispose(); super.dispose(); } @@ -796,16 +805,18 @@ class _LoginState extends State { ) else InkWell( - onTap: () => launchUrl(Uri.parse(kDocsUrl)), + onTap: () => setState(() { + _showSettings = !_showSettings; + }), child: Padding( padding: const EdgeInsets.all(14), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.book, size: 16), + Icon(Icons.settings, size: 16), SizedBox(width: 8), - Text(localization!.documentation) + Text(localization!.settings) ], ), ), @@ -815,7 +826,38 @@ class _LoginState extends State { ), ], ), - SizedBox(height: 20), + SizedBox(height: 8), + if (_showSettings) ...[ + FormCard( + forceNarrow: true, + internalPadding: const EdgeInsets.all(0), + children: [ + Padding( + padding: EdgeInsets.symmetric( + horizontal: horizontalPadding, vertical: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + DecoratedFormField( + autofocus: true, + hint: 'domain.com', + label: localization!.sslHostOverride, + controller: _hostOverrideController, + keyboardType: TextInputType.text, + onChanged: (value) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(kSharedPrefHostOverride, value); + }, + ), + SizedBox(height: 8), + Text(localization.restartAppToApplyChange), + ], + ), + ), + ], + ), + SizedBox(height: 20), + ] ], ), ); diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index 0cc822aaf6..99334c2e0b 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -18,6 +18,7 @@ mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { // STARTER: lang key - do not remove comment + 'ssl_host_override': 'SSL Host Override', 'upload_logo_short': 'Upload Logo', 'show_pdfhtml_on_mobile_help': 'For improved visualization, displays a HTML version of the invoice/quote when viewing on mobile.', @@ -118092,6 +118093,10 @@ mixin LocalizationsProvider on LocaleCodeAware { _localizedValues[localeCode]!['upload_logo_short'] ?? _localizedValues['en']!['upload_logo_short']!; + String get sslHostOverride => + _localizedValues[localeCode]!['ssl_host_override'] ?? + _localizedValues['en']!['ssl_host_override']!; + // STARTER: lang field - do not remove comment String lookup(String? key, {String? overrideLocaleCode}) { diff --git a/pubspec.foss.yaml b/pubspec.foss.yaml index c23f71f043..e10f94c4a9 100644 --- a/pubspec.foss.yaml +++ b/pubspec.foss.yaml @@ -1,6 +1,6 @@ name: invoiceninja_flutter description: Client for Invoice Ninja -version: 5.0.162+162 +version: 5.0.163+163 homepage: https://invoiceninja.com documentation: https://invoiceninja.github.io publish_to: none diff --git a/pubspec.yaml b/pubspec.yaml index b7111161c1..9315b6acd1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: invoiceninja_flutter description: Client for Invoice Ninja -version: 5.0.162+162 +version: 5.0.163+163 homepage: https://invoiceninja.com documentation: https://invoiceninja.github.io publish_to: none diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index c2fd96da72..9b414839b6 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: invoiceninja -version: '5.0.162' +version: '5.0.163' summary: Create invoices, accept payments, track expenses & time tasks description: "### Note: if the app fails to run using `snap run invoiceninja` it may help to run `/snap/invoiceninja/current/bin/invoiceninja` instead