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