This commit was merged in pull request #263.
This commit is contained in:
@@ -15,6 +15,11 @@ import io.flutter.embedding.engine.FlutterEngine;
|
|||||||
public final class GeneratedPluginRegistrant {
|
public final class GeneratedPluginRegistrant {
|
||||||
private static final String TAG = "GeneratedPluginRegistrant";
|
private static final String TAG = "GeneratedPluginRegistrant";
|
||||||
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
|
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
|
||||||
|
try {
|
||||||
|
flutterEngine.getPlugins().add(new dev.fluttercommunity.plus.device_info.DeviceInfoPlusPlugin());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error registering plugin device_info_plus, dev.fluttercommunity.plus.device_info.DeviceInfoPlusPlugin", e);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
flutterEngine.getPlugins().add(new com.mr.flutter.plugin.filepicker.FilePickerPlugin());
|
flutterEngine.getPlugins().add(new com.mr.flutter.plugin.filepicker.FilePickerPlugin());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
const int dbSchemaVersion = 32;
|
||||||
@@ -6,6 +6,7 @@ import 'package:drift/native.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:sharedinbox/core/db_schema_version.dart';
|
||||||
|
|
||||||
part 'database.g.dart';
|
part 'database.g.dart';
|
||||||
|
|
||||||
@@ -329,7 +330,7 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());
|
AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 32;
|
int get schemaVersion => dbSchemaVersion;
|
||||||
|
|
||||||
Future<void> _createEmailFts() async {
|
Future<void> _createEmailFts() async {
|
||||||
await customStatement('''
|
await customStatement('''
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:sharedinbox/core/db_schema_version.dart';
|
||||||
import 'package:sharedinbox/core/models/account.dart';
|
import 'package:sharedinbox/core/models/account.dart';
|
||||||
import 'package:sharedinbox/di.dart';
|
import 'package:sharedinbox/di.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@@ -19,7 +21,9 @@ class AboutScreen extends ConsumerStatefulWidget {
|
|||||||
|
|
||||||
class _AboutScreenState extends ConsumerState<AboutScreen> {
|
class _AboutScreenState extends ConsumerState<AboutScreen> {
|
||||||
final Future<PackageInfo> _packageInfoFuture = PackageInfo.fromPlatform();
|
final Future<PackageInfo> _packageInfoFuture = PackageInfo.fromPlatform();
|
||||||
|
late final Future<String?> _deviceModelFuture;
|
||||||
late final Stream<List<Account>> _accountsStream;
|
late final Stream<List<Account>> _accountsStream;
|
||||||
|
String? _deviceModel;
|
||||||
|
|
||||||
static const _gitHash = String.fromEnvironment('GIT_HASH');
|
static const _gitHash = String.fromEnvironment('GIT_HASH');
|
||||||
|
|
||||||
@@ -27,14 +31,35 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_accountsStream = ref.read(accountRepositoryProvider).observeAccounts();
|
_accountsStream = ref.read(accountRepositoryProvider).observeAccounts();
|
||||||
|
_deviceModelFuture = _fetchDeviceModel();
|
||||||
|
unawaited(
|
||||||
|
_deviceModelFuture.then((model) {
|
||||||
|
if (mounted) setState(() => _deviceModel = model);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String?> _fetchDeviceModel() async {
|
||||||
|
try {
|
||||||
|
final info = DeviceInfoPlugin();
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
final android = await info.androidInfo;
|
||||||
|
return '${android.manufacturer} / ${android.model}';
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
final ios = await info.iosInfo;
|
||||||
|
return ios.utsname.machine;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _buildMarkdown(
|
String _buildMarkdown(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
PackageInfo? pkg,
|
PackageInfo? pkg,
|
||||||
int imapCount,
|
int imapCount,
|
||||||
int jmapCount,
|
int jmapCount, {
|
||||||
) {
|
String? deviceModel,
|
||||||
|
}) {
|
||||||
final size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
final pixelRatio = MediaQuery.of(context).devicePixelRatio;
|
final pixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
final physW = (size.width * pixelRatio).toInt();
|
final physW = (size.width * pixelRatio).toInt();
|
||||||
@@ -46,10 +71,15 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
|
|||||||
: version;
|
: version;
|
||||||
final osName = _capitalize(Platform.operatingSystem);
|
final osName = _capitalize(Platform.operatingSystem);
|
||||||
final isDark = MediaQuery.of(context).platformBrightness == Brightness.dark;
|
final isDark = MediaQuery.of(context).platformBrightness == Brightness.dark;
|
||||||
|
final locale = Localizations.localeOf(context).toString();
|
||||||
|
final textScale =
|
||||||
|
MediaQuery.of(context).textScaler.scale(1.0).toStringAsFixed(1);
|
||||||
|
|
||||||
final gitCommitLine = _gitHash.isNotEmpty
|
final gitCommitLine = _gitHash.isNotEmpty
|
||||||
? '| Git Commit | [$_gitHash](https://codeberg.org/guettli/sharedinbox/commit/$_gitHash) |\n'
|
? '| Git Commit | [$_gitHash](https://codeberg.org/guettli/sharedinbox/commit/$_gitHash) |\n'
|
||||||
: '';
|
: '';
|
||||||
|
final deviceModelLine =
|
||||||
|
deviceModel != null ? '| Device Model | $deviceModel |\n' : '';
|
||||||
return '## [sharedinbox.de](https://sharedinbox.de)\n\n'
|
return '## [sharedinbox.de](https://sharedinbox.de)\n\n'
|
||||||
'| Property | Value |\n'
|
'| Property | Value |\n'
|
||||||
'|----------|-------|\n'
|
'|----------|-------|\n'
|
||||||
@@ -57,12 +87,16 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
|
|||||||
'$gitCommitLine'
|
'$gitCommitLine'
|
||||||
'| Platform | ${Platform.operatingSystem} |\n'
|
'| Platform | ${Platform.operatingSystem} |\n'
|
||||||
'| $osName Version | ${Platform.operatingSystemVersion} |\n'
|
'| $osName Version | ${Platform.operatingSystemVersion} |\n'
|
||||||
|
'$deviceModelLine'
|
||||||
'| Resolution | ${physW}x$physH px'
|
'| Resolution | ${physW}x$physH px'
|
||||||
' (logical: ${size.width.toInt()}x${size.height.toInt()} pt,'
|
' (logical: ${size.width.toInt()}x${size.height.toInt()} pt,'
|
||||||
' ratio: ${pixelRatio.toStringAsFixed(1)}x) |\n'
|
' ratio: ${pixelRatio.toStringAsFixed(1)}x) |\n'
|
||||||
'| Dart Version | ${Platform.version.split(' ').first} |\n'
|
'| Dart Version | ${Platform.version.split(' ').first} |\n'
|
||||||
'| Processors | ${Platform.numberOfProcessors} |\n'
|
'| Processors | ${Platform.numberOfProcessors} |\n'
|
||||||
'| Dark Mode | ${isDark ? 'yes' : 'no'} |\n'
|
'| Dark Mode | ${isDark ? 'yes' : 'no'} |\n'
|
||||||
|
'| Locale | $locale |\n'
|
||||||
|
'| Text Scale | $textScale× |\n'
|
||||||
|
'| DB Schema Version | $dbSchemaVersion |\n'
|
||||||
'| IMAP Accounts | $imapCount |\n'
|
'| IMAP Accounts | $imapCount |\n'
|
||||||
'| JMAP Accounts | $jmapCount |\n';
|
'| JMAP Accounts | $jmapCount |\n';
|
||||||
}
|
}
|
||||||
@@ -79,10 +113,20 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
|
|||||||
try {
|
try {
|
||||||
pkg = await _packageInfoFuture;
|
pkg = await _packageInfoFuture;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
String? deviceModel;
|
||||||
|
try {
|
||||||
|
deviceModel = await _deviceModelFuture;
|
||||||
|
} catch (_) {}
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
await Clipboard.setData(
|
await Clipboard.setData(
|
||||||
ClipboardData(
|
ClipboardData(
|
||||||
text: _buildMarkdown(context, pkg, imapCount, jmapCount),
|
text: _buildMarkdown(
|
||||||
|
context,
|
||||||
|
pkg,
|
||||||
|
imapCount,
|
||||||
|
jmapCount,
|
||||||
|
deviceModel: deviceModel,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
@@ -128,9 +172,19 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
|
|||||||
try {
|
try {
|
||||||
pkg = await _packageInfoFuture;
|
pkg = await _packageInfoFuture;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
String? deviceModel;
|
||||||
|
try {
|
||||||
|
deviceModel = await _deviceModelFuture;
|
||||||
|
} catch (_) {}
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
final body = Uri.encodeComponent(
|
final body = Uri.encodeComponent(
|
||||||
_buildMarkdown(context, pkg, imapCount, jmapCount),
|
_buildMarkdown(
|
||||||
|
context,
|
||||||
|
pkg,
|
||||||
|
imapCount,
|
||||||
|
jmapCount,
|
||||||
|
deviceModel: deviceModel,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
final url = Uri.parse(
|
final url = Uri.parse(
|
||||||
'https://codeberg.org/guettli/sharedinbox/issues/new?body=$body',
|
'https://codeberg.org/guettli/sharedinbox/issues/new?body=$body',
|
||||||
@@ -186,6 +240,7 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
|
|||||||
snapshot.data,
|
snapshot.data,
|
||||||
imapCount,
|
imapCount,
|
||||||
jmapCount,
|
jmapCount,
|
||||||
|
deviceModel: _deviceModel,
|
||||||
),
|
),
|
||||||
selectable: true,
|
selectable: true,
|
||||||
onTapLink: (text, href, title) {
|
onTapLink: (text, href, title) {
|
||||||
|
|||||||
@@ -249,6 +249,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.12"
|
version: "0.7.12"
|
||||||
|
device_info_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: device_info_plus
|
||||||
|
sha256: "6a642e1daa10190af89ba6cb6386c0df7d071a3592080bfe1e44faa63ae1df65"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.1.0"
|
||||||
|
device_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_platform_interface
|
||||||
|
sha256: "04b173a92e2d9161dfead145667037c8d834db725ce2e7b942bfe18fd2f45a46"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.1.0"
|
||||||
drift:
|
drift:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1284,6 +1300,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.0"
|
version: "6.3.0"
|
||||||
|
win32_registry:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32_registry
|
||||||
|
sha256: "73b1d78920a9d6e03f8b4e43e612b87bf3152a0e5c5e5150267762b7c4116904"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
workmanager:
|
workmanager:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ dependencies:
|
|||||||
# App version metadata for crash reports
|
# App version metadata for crash reports
|
||||||
package_info_plus: ^10.1.0
|
package_info_plus: ^10.1.0
|
||||||
share_plus: ^13.1.0
|
share_plus: ^13.1.0
|
||||||
|
device_info_plus: ^13.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const _minCoveragePercent = 80;
|
|||||||
|
|
||||||
// Pure-abstract interfaces: no executable code, Dart VM never instruments them.
|
// Pure-abstract interfaces: no executable code, Dart VM never instruments them.
|
||||||
const _noCode = {
|
const _noCode = {
|
||||||
|
'lib/core/db_schema_version.dart',
|
||||||
'lib/core/repositories/account_repository.dart',
|
'lib/core/repositories/account_repository.dart',
|
||||||
'lib/core/repositories/draft_repository.dart',
|
'lib/core/repositories/draft_repository.dart',
|
||||||
'lib/core/repositories/email_repository.dart',
|
'lib/core/repositories/email_repository.dart',
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ void main() {
|
|||||||
expect(find.textContaining('Dark Mode'), findsWidgets);
|
expect(find.textContaining('Dark Mode'), findsWidgets);
|
||||||
expect(find.textContaining('IMAP Accounts'), findsWidgets);
|
expect(find.textContaining('IMAP Accounts'), findsWidgets);
|
||||||
expect(find.textContaining('JMAP Accounts'), findsWidgets);
|
expect(find.textContaining('JMAP Accounts'), findsWidgets);
|
||||||
|
expect(find.textContaining('Locale'), findsWidgets);
|
||||||
|
expect(find.textContaining('Text Scale'), findsWidgets);
|
||||||
|
expect(find.textContaining('DB Schema Version'), findsWidgets);
|
||||||
// Buttons are in the body, not in the AppBar actions
|
// Buttons are in the body, not in the AppBar actions
|
||||||
expect(find.byIcon(Icons.copy), findsOneWidget);
|
expect(find.byIcon(Icons.copy), findsOneWidget);
|
||||||
expect(find.byIcon(Icons.bug_report), findsOneWidget);
|
expect(find.byIcon(Icons.bug_report), findsOneWidget);
|
||||||
@@ -167,6 +170,9 @@ void main() {
|
|||||||
expect(clipboardText, contains('Dark Mode'));
|
expect(clipboardText, contains('Dark Mode'));
|
||||||
expect(clipboardText, contains('IMAP Accounts'));
|
expect(clipboardText, contains('IMAP Accounts'));
|
||||||
expect(clipboardText, contains('JMAP Accounts'));
|
expect(clipboardText, contains('JMAP Accounts'));
|
||||||
|
expect(clipboardText, contains('Locale'));
|
||||||
|
expect(clipboardText, contains('Text Scale'));
|
||||||
|
expect(clipboardText, contains('DB Schema Version'));
|
||||||
expect(
|
expect(
|
||||||
clipboardText,
|
clipboardText,
|
||||||
contains('[sharedinbox.de](https://sharedinbox.de)'),
|
contains('[sharedinbox.de](https://sharedinbox.de)'),
|
||||||
|
|||||||
Reference in New Issue
Block a user