Browse Source

Merge pull request #840 from nextcloud/feature/automatic-spell-checking

Feature/automatic spell checking
pull/850/head
Kate 1 year ago committed by GitHub
parent
commit
b49f49da32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      .cspell/dart_flutter.txt
  2. 11
      .cspell/misc.txt
  3. 20
      .cspell/neon.txt
  4. 71
      .cspell/nextcloud.txt
  5. 60
      .cspell/tools.txt
  6. 50
      .cspell/webdav.txt
  7. 10
      .github/workflows/spellcheck.yaml
  8. 2
      README.md
  9. 60
      cspell.json
  10. 2
      external/nextcloud-notifications
  11. 2
      packages/file_icons/bin/file_icons.dart
  12. 4
      packages/neon/neon/lib/l10n/en.arb
  13. 8
      packages/neon/neon/lib/l10n/localizations.dart
  14. 4
      packages/neon/neon/lib/l10n/localizations_en.dart
  15. 2
      packages/neon/neon/lib/models.dart
  16. 60
      packages/neon/neon/lib/src/models/account.dart
  17. 6
      packages/neon/neon/lib/src/models/disposable.dart
  18. 4
      packages/neon/neon/lib/src/pages/login.dart
  19. 14
      packages/neon/neon/lib/src/pages/login_qr_code.dart
  20. 4
      packages/neon/neon/lib/src/pages/route_not_found.dart
  21. 2
      packages/neon/neon/lib/src/pages/settings.dart
  22. 40
      packages/neon/neon/lib/src/router.dart
  23. 26
      packages/neon/neon/lib/src/router.g.dart
  24. 4
      packages/neon/neon/lib/src/theme/colors.dart
  25. 2
      packages/neon/neon/lib/src/utils/exceptions.dart
  26. 8
      packages/neon/neon/lib/src/utils/global_options.dart
  27. 2
      packages/neon/neon/lib/src/utils/relative_time.dart
  28. 8
      packages/neon/neon/lib/src/widgets/drawer_destination.dart
  29. 4
      packages/neon/neon/lib/src/widgets/exception.dart
  30. 12
      packages/neon/neon/test/account_test.dart
  31. 2
      packages/neon/neon/test/result_test.dart
  32. 1
      packages/neon/neon_news/lib/blocs/news.dart
  33. 2
      packages/nextcloud/lib/src/api/notifications.openapi.json
  34. 2
      packages/nextcloud/lib/src/webdav/file.dart
  35. 8
      tool/update-cspell-dictionaries.sh

9
.cspell/dart_flutter.txt

@ -0,0 +1,9 @@
autofocus
gapless
lerp
pubspec
sublist
todos
unawaited
unfocus
writeln

11
.cspell/misc.txt

@ -0,0 +1,11 @@
browsable
cleartext
deeplinking
flathub
foss
fullscreen
playstore
postmarket
provokateurin
subroutes
uncategorized

20
.cspell/neon.txt

@ -0,0 +1,20 @@
crypton
exportables
fcmup
filesize
gotify
heckel
mocktail
nextpush
noprovider
ntfy
oled
oledas
rxdart
seti
siacs
sqflite
underspecified
updateshouldnotify
wakelock
zxing

71
.cspell/nextcloud.txt

@ -0,0 +1,71 @@
apirequest
applist
apppassword
approximative
appstore
bigfilechunking
bools
bulkupload
commenters
csapi
datetime
deletedshares
displayname
etag
fediverse
getapppassword
groupid
hovercard
iscustomavatar
itemsperpage
keepalive
keypair
lastmod
licence
logfile
logoheader
mimetypes
mountpoint
navigations
nextcloud
nextcloud's
openlocaleditor
organisation
prio
productname
publicpreview
reshares
resharing
rgdnvw
r'sharebymail
r'updatenotification
r'uppush
shareapi
sharebymail
sharee
shareesapi
shareinfo
statuscode
stime
stylesheet
subadmin
subadmins
subfiles
subline
tasktypes
textprocessing
totalitems
transferownership
trashbin
undelete
unifiedpush
unsharing
unstar
updatenotification
uppush
usercount
usergroup
userid
userroom
versionstring
whatsnew

60
.cspell/tools.txt

@ -0,0 +1,60 @@
aarch
allprojects
appindicator
autoptr
buildscript
buildsystem
buildx
cest
classpath
cloc
commitlint
dapplication
dists
endforeach
endfunction
endlegend
endswith
enduml
euxo
exiftool
extglob
freedesktop
fullpath
gboolean
gchar
genhtml
gradlew
hicolor
icudtl
inkscape
intellij
jetbrains
jvmargs
klass
lcov
libapp
libappindicator
libayatana
libflutter
libindicator
libsqlite
mipmap
ndebug
nproc
plantuml
precache
puml
rpath
startuml
stdlib
strconcat
strdupv
strfreev
subprojects
sysroot
tsvg
werror
workdir
xxxh
xxxhdpi

50
.cspell/webdav.txt

@ -0,0 +1,50 @@
copymove
dasl
davgetcontentlength
davgetcontenttype
davgetetag
davgetlastmodified
davresourcetype
fileid
getcontentlength
getcontenttype
getetag
getlastmodified
largefile
mkcol
multistatus
nccreationtime
ncdatafingerprint
nchaspreview
ncisencrypted
ncmetadataetag
ncmounttype
ncnote
ncrichworkspace
ncuploadtime
nodestcoll
noncoll
noparent
occommentscount
occommentshref
occommentsunread
ocdownloadurl
ocfavorite
ocfileid
ocid
ocmsharepermissions
ocownerdisplayname
ocownerid
ocpermissions
ocsize
ocssharepermissions
owncloud
propertyupdate
propfind
proppatch
propstat
propstats
resourcetype
sharees
systemtag
webdav

10
.github/workflows/spellcheck.yaml

@ -0,0 +1,10 @@
name: 'Check spelling'
on:
pull_request:
jobs:
spellcheck:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: streetsidesoftware/cspell-action@v3

2
README.md

@ -22,7 +22,7 @@ The Neon project has three main goals:
The Neon project uses [Dart](https://dart.dev/) and [Flutter](https://flutter.dev/) to help mobile client developers building apps. Flutter allows us to build convergent cross-platform clients that feel native.
We are a 100% FOSS framework and do not rely on any proprietary libraries making it easy for developers to publish their apps in places like the [F-Droid](https://f-droid.org/) store.
We provide a generated [Nextcloud Dart client](packages/nextcloud) that is generated from the new OpenAPI specifications shipped with Nextcloud and is already being used by other Dart and Flutter projects. Gone are the days of looking at the PHP code and implementing an API client by hand wich can be time-consuming and very error-prone.
We provide a generated [Nextcloud Dart client](packages/nextcloud) that is generated from the new OpenAPI specifications shipped with Nextcloud and is already being used by other Dart and Flutter projects. Gone are the days of looking at the PHP code and implementing an API client by hand which can be time-consuming and very error-prone.
We provide abstractions, common utilities and prebuilt UI components (called Widgets in Flutter) that can be re-used. This allows Neon to make developing a new Nextcloud client as easy as adding a few custom UI elements and the necessary state management, while everything else is already taken care of for you.

60
cspell.json

@ -0,0 +1,60 @@
{
"version": "0.2",
"language": "en",
"words": [
"OpenAPI"
],
"ignorePaths": [
"**.iml",
"**.log",
"**.svg",
"**/assets/**",
"**/build/**",
"**/coverage/**",
"**/ephemeral/**",
"**/l10n/!(en.arb)",
"external",
"packages/app/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java",
"packages/app/android/gradlew*",
"packages/file_icons/lib/src/data.dart",
"packages/neon_lints/lib",
"packages/nextcloud/test/files"
],
"dictionaries": [
"bash",
"dart_flutter",
"en_US",
"misc",
"neon",
"nextcloud",
"softwareTerms",
"tools",
"webdav"
],
"dictionaryDefinitions": [
{
"name": "dart_flutter",
"path": ".cspell/dart_flutter.txt"
},
{
"name": "misc",
"path": ".cspell/misc.txt"
},
{
"name": "neon",
"path": ".cspell/neon.txt"
},
{
"name": "nextcloud",
"path": ".cspell/nextcloud.txt"
},
{
"name": "tools",
"path": ".cspell/tools.txt"
},
{
"name": "webdav",
"path": ".cspell/webdav.txt"
}
]
}

2
external/nextcloud-notifications vendored

@ -1 +1 @@
Subproject commit 9e4bfdcf04d3a17402f4b22166e1afd4fc7ff833
Subproject commit 8056d80ce22aeef0a65c3f2523869e7ea0f37f54

2
packages/file_icons/bin/file_icons.dart

@ -98,7 +98,7 @@ void generateData() {
"import 'package:flutter/widgets.dart';",
'',
'// Code points',
// This filters unused codepoints.
// This filters unused code points.
for (final type in codePoints.keys
.where((final type) => iconSet.keys.map((final pattern) => iconSet[pattern]![0] == type).contains(true))) ...[
'const ${_toVariableName(type)} = ${codePoints[type]};',

4
packages/neon/neon/lib/l10n/en.arb

@ -12,7 +12,7 @@
"loginOpenAgain": "Open again",
"loginSwitchToBrowserWindow": "Please switch to the browser window that just opened and proceed there",
"loginWorksWith": "works with",
"loginUsingQrcode": "Login using a QR code",
"loginUsingQRcode": "Login using a QR code",
"loginUsingServerAddress": "Login using the server address",
"loginCheckingServerVersion": "Checking server version",
"loginSupportedServerVersion": "Supported server version: {version}",
@ -69,7 +69,7 @@
},
"errorEmptyField": "This field can not be empty",
"errorInvalidURL": "Invalid URL provided",
"errorInvalidQrcode": "Invalid QR-Code provided",
"errorInvalidQRcode": "Invalid QR-Code provided",
"errorRouteNotFound": "Route not found: {route}",
"@errorRouteNotFound" : {
"placeholders": {

8
packages/neon/neon/lib/l10n/localizations.dart

@ -131,11 +131,11 @@ abstract class AppLocalizations {
/// **'works with'**
String get loginWorksWith;
/// No description provided for @loginUsingQrcode.
/// No description provided for @loginUsingQRcode.
///
/// In en, this message translates to:
/// **'Login using a QR code'**
String get loginUsingQrcode;
String get loginUsingQRcode;
/// No description provided for @loginUsingServerAddress.
///
@ -263,11 +263,11 @@ abstract class AppLocalizations {
/// **'Invalid URL provided'**
String get errorInvalidURL;
/// No description provided for @errorInvalidQrcode.
/// No description provided for @errorInvalidQRcode.
///
/// In en, this message translates to:
/// **'Invalid QR-Code provided'**
String get errorInvalidQrcode;
String get errorInvalidQRcode;
/// No description provided for @errorRouteNotFound.
///

4
packages/neon/neon/lib/l10n/localizations_en.dart

@ -42,7 +42,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get loginWorksWith => 'works with';
@override
String get loginUsingQrcode => 'Login using a QR code';
String get loginUsingQRcode => 'Login using a QR code';
@override
String get loginUsingServerAddress => 'Login using the server address';
@ -121,7 +121,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get errorInvalidURL => 'Invalid URL provided';
@override
String get errorInvalidQrcode => 'Invalid QR-Code provided';
String get errorInvalidQRcode => 'Invalid QR-Code provided';
@override
String errorRouteNotFound(String route) {

2
packages/neon/neon/lib/models.dart

@ -1,4 +1,4 @@
export 'package:neon/src/models/account.dart' hide Credentials, LoginQrcode;
export 'package:neon/src/models/account.dart' hide Credentials, LoginQRcode;
export 'package:neon/src/models/app_ids.dart';
export 'package:neon/src/models/app_implementation.dart';
export 'package:neon/src/models/notifications_interface.dart';

60
packages/neon/neon/lib/src/models/account.dart

@ -117,16 +117,16 @@ extension AccountFind on Iterable<Account> {
Account find(final String accountID) => firstWhere((final account) => account.id == accountID);
}
/// Qrcode Login credentials.
/// QRcode Login credentials.
///
/// The Credentials as provided by the server when manually creating an app
/// password.
@internal
@immutable
class LoginQrcode implements Credentials {
/// Creates a new LoginQrcode object.
class LoginQRcode implements Credentials {
/// Creates a new LoginQRcode object.
@visibleForTesting
const LoginQrcode({
const LoginQRcode({
required this.serverURL,
required this.username,
required this.password,
@ -139,31 +139,31 @@ class LoginQrcode implements Credentials {
@override
final String password;
/// Pattern matching the full Qrcode content.
static final _loginQrcodeUrlRegex = RegExp(r'^nc://login/user:(.*)&password:(.*)&server:(.*)$');
/// Pattern matching the full QRcode content.
static final _loginQRcodeUrlRegex = RegExp(r'^nc://login/user:(.*)&password:(.*)&server:(.*)$');
/// Pattern matching the path part of the Qrcode.
/// Pattern matching the path part of the QRcode.
///
/// This is used when launching the app through an intent.
static final _loginQrcodePathRegex = RegExp(r'^/user:(.*)&password:(.*)&server:(.*)$');
static final _loginQRcodePathRegex = RegExp(r'^/user:(.*)&password:(.*)&server:(.*)$');
/// Creates a new `LoginQrcode` object by parsing a url string.
/// Creates a new `LoginQRcode` object by parsing a url string.
///
/// If the [url] string is not valid as a LoginQrcode a [FormatException] is
/// If the [url] string is not valid as a LoginQRcode a [FormatException] is
/// thrown.
///
/// Example:
/// ```dart
/// final loginQrcode =
/// LoginQrcode.parse('nc://login/user:JohnDoe&password:super_secret&server:example.com');
/// print(loginQrcode.serverURL); // JohnDoe
/// print(loginQrcode.username); // super_secret
/// print(loginQrcode.password); // example.com
/// final loginQRcode =
/// LoginQRcode.parse('nc://login/user:JohnDoe&password:super_secret&server:example.com');
/// print(loginQRcode.serverURL); // JohnDoe
/// print(loginQRcode.username); // super_secret
/// print(loginQRcode.password); // example.com
///
/// LoginQrcode.parse('::Not valid LoginQrcode::'); // Throws FormatException.
/// LoginQRcode.parse('::Not valid LoginQRcode::'); // Throws FormatException.
/// ```
static LoginQrcode parse(final String url) {
for (final regex in [_loginQrcodeUrlRegex, _loginQrcodePathRegex]) {
static LoginQRcode parse(final String url) {
for (final regex in [_loginQRcodeUrlRegex, _loginQRcodePathRegex]) {
final matches = regex.allMatches(url);
if (matches.isEmpty) {
continue;
@ -174,7 +174,7 @@ class LoginQrcode implements Credentials {
continue;
}
return LoginQrcode(
return LoginQRcode(
serverURL: Uri.parse(match.group(3)!),
username: match.group(1)!,
password: match.group(2)!,
@ -184,22 +184,22 @@ class LoginQrcode implements Credentials {
throw const FormatException();
}
/// Creates a new `LoginQrcode` object by parsing a url string.
/// Creates a new `LoginQRcode` object by parsing a url string.
///
/// Returns `null` if the [url] string is not valid as a LoginQrcode.
/// Returns `null` if the [url] string is not valid as a LoginQRcode.
///
/// Example:
/// ```dart
/// final loginQrcode =
/// LoginQrcode.parse('nc://login/user:JohnDoe&password:super_secret&server:example.com');
/// print(loginQrcode.serverURL); // JohnDoe
/// print(loginQrcode.username); // super_secret
/// print(loginQrcode.password); // example.com
/// final loginQRcode =
/// LoginQRcode.parse('nc://login/user:JohnDoe&password:super_secret&server:example.com');
/// print(loginQRcode.serverURL); // JohnDoe
/// print(loginQRcode.username); // super_secret
/// print(loginQRcode.password); // example.com
///
/// final notLoginQrcode = LoginQrcode.tryParse('::Not valid LoginQrcode::');
/// print(notLoginQrcode); // null
/// final notLoginQRcode = LoginQRcode.tryParse('::Not valid LoginQRcode::');
/// print(notLoginQRcode); // null
/// ```
static LoginQrcode? tryParse(final String url) {
static LoginQRcode? tryParse(final String url) {
try {
return parse(url);
} on FormatException {
@ -209,7 +209,7 @@ class LoginQrcode implements Credentials {
@override
bool operator ==(final Object other) =>
other is LoginQrcode && other.serverURL == serverURL && other.username == username && other.password == password;
other is LoginQRcode && other.serverURL == serverURL && other.username == username && other.password == password;
@override
int get hashCode => Object.hashAll([

6
packages/neon/neon/lib/src/models/disposable.dart

@ -11,10 +11,10 @@ abstract interface class Disposable {
void dispose();
}
extension DisposeableIterableBloc on Iterable<Disposable> {
extension DisposableIterableBloc on Iterable<Disposable> {
/// Calls [Disposable.dispose] on all entries.
///
/// The disposed values will not be removed from the iteraable.
/// The disposed values will not be removed from the iterable.
void disposeAll() {
for (final bloc in this) {
bloc.dispose();
@ -22,7 +22,7 @@ extension DisposeableIterableBloc on Iterable<Disposable> {
}
}
extension DisposeableMapBloc on Map<dynamic, Disposable> {
extension DisposableMapBloc on Map<dynamic, Disposable> {
/// Calls [Disposable.dispose] on all entries.
///
/// The disposed values will not be removed from the map.

4
packages/neon/neon/lib/src/pages/login.dart

@ -108,12 +108,12 @@ class _LoginPageState extends State<LoginPage> {
height: 50,
),
IconButton(
tooltip: AppLocalizations.of(context).loginUsingQrcode,
tooltip: AppLocalizations.of(context).loginUsingQRcode,
icon: const Icon(
Icons.qr_code_scanner_rounded,
size: 60,
),
onPressed: () => const LoginQrcodeRoute().go(context),
onPressed: () => const LoginQRcodeRoute().go(context),
),
],
],

14
packages/neon/neon/lib/src/pages/login_qrcode.dart → packages/neon/neon/lib/src/pages/login_qr_code.dart

@ -7,16 +7,16 @@ import 'package:neon/src/utils/exceptions.dart';
import 'package:neon/src/widgets/exception.dart';
@internal
class LoginQrcodePage extends StatefulWidget {
const LoginQrcodePage({
class LoginQRcodePage extends StatefulWidget {
const LoginQRcodePage({
super.key,
});
@override
State<LoginQrcodePage> createState() => _LoginQrcodePageState();
State<LoginQRcodePage> createState() => _LoginQRcodePageState();
}
class _LoginQrcodePageState extends State<LoginQrcodePage> {
class _LoginQRcodePageState extends State<LoginQRcodePage> {
String? _lastErrorURL;
@override
@ -35,11 +35,11 @@ class _LoginQrcodePageState extends State<LoginQrcodePage> {
try {
url = code.text;
if (url == null) {
throw InvalidQrcodeException();
throw InvalidQRcodeException();
}
final match = LoginQrcode.tryParse(url);
final match = LoginQRcode.tryParse(url);
if (match == null) {
throw InvalidQrcodeException();
throw InvalidQRcodeException();
}
LoginCheckServerStatusRoute.withCredentials(

4
packages/neon/neon/lib/src/pages/route_not_found.dart

@ -26,10 +26,10 @@ class _RouteNotFoundPageState extends State<RouteNotFoundPage> {
void initState() {
super.initState();
unawaited(_checkLaunchable());
unawaited(_checkCanLaunch());
}
Future<void> _checkLaunchable() async {
Future<void> _checkCanLaunch() async {
final accountsBloc = NeonProvider.of<AccountsBloc>(context);
if (!accountsBloc.hasAccounts) {
return;

2
packages/neon/neon/lib/src/pages/settings.dart

@ -208,7 +208,7 @@ class _SettingsPageState extends State<SettingsPage> {
AccountSettingsTile(
account: account,
onTap: () {
AccountSettingsRoute(accountid: account.id).go(context);
AccountSettingsRoute(accountID: account.id).go(context);
},
),
],

40
packages/neon/neon/lib/src/router.dart

@ -15,7 +15,7 @@ import 'package:neon/src/pages/login.dart';
import 'package:neon/src/pages/login_check_account.dart';
import 'package:neon/src/pages/login_check_server_status.dart';
import 'package:neon/src/pages/login_flow.dart';
import 'package:neon/src/pages/login_qrcode.dart';
import 'package:neon/src/pages/login_qr_code.dart';
import 'package:neon/src/pages/nextcloud_app_settings.dart';
import 'package:neon/src/pages/route_not_found.dart';
import 'package:neon/src/pages/settings.dart';
@ -36,12 +36,12 @@ class AppRouter extends GoRouter {
initialLocation: const HomeRoute().location,
errorPageBuilder: _buildErrorPage,
redirect: (final context, final state) {
final loginQrcode = LoginQrcode.tryParse(state.uri.toString());
if (loginQrcode != null) {
final loginQRcode = LoginQRcode.tryParse(state.uri.toString());
if (loginQRcode != null) {
return LoginCheckServerStatusRoute.withCredentials(
serverUrl: loginQrcode.serverURL,
loginName: loginQrcode.username,
password: loginQrcode.password,
serverUrl: loginQRcode.serverURL,
loginName: loginQRcode.username,
password: loginQRcode.password,
).location;
}
@ -72,15 +72,15 @@ class AppRouter extends GoRouter {
@immutable
class AccountSettingsRoute extends GoRouteData {
const AccountSettingsRoute({
required this.accountid,
required this.accountID,
});
final String accountid;
final String accountID;
@override
Widget build(final BuildContext context, final GoRouterState state) {
final bloc = NeonProvider.of<AccountsBloc>(context);
final account = bloc.accounts.value.find(accountid);
final account = bloc.accounts.value.find(accountID);
return AccountSettingsPage(
bloc: bloc,
@ -108,8 +108,8 @@ class AccountSettingsRoute extends GoRouteData {
TypedGoRoute<_AddAccountFlowRoute>(
path: 'flow',
),
TypedGoRoute<_AddAccountQrcodeRoute>(
path: 'qrcode',
TypedGoRoute<_AddAccountQRcodeRoute>(
path: 'qr-code',
),
TypedGoRoute<_AddAccountCheckServerStatusRoute>(
path: 'check/server',
@ -120,7 +120,7 @@ class AccountSettingsRoute extends GoRouteData {
],
),
TypedGoRoute<AccountSettingsRoute>(
path: 'account/:accountid',
path: 'account/:accountID',
name: 'AccountSettings',
),
],
@ -147,8 +147,8 @@ class HomeRoute extends GoRouteData {
TypedGoRoute<LoginFlowRoute>(
path: 'flow',
),
TypedGoRoute<LoginQrcodeRoute>(
path: 'qrcode',
TypedGoRoute<LoginQRcodeRoute>(
path: 'qr-code',
),
TypedGoRoute<LoginCheckServerStatusRoute>(
path: 'check/server',
@ -201,18 +201,18 @@ class LoginFlowRoute extends GoRouteData {
}
@immutable
class LoginQrcodeRoute extends GoRouteData {
const LoginQrcodeRoute();
class LoginQRcodeRoute extends GoRouteData {
const LoginQRcodeRoute();
@override
Widget build(final BuildContext context, final GoRouterState state) => const LoginQrcodePage();
Widget build(final BuildContext context, final GoRouterState state) => const LoginQRcodePage();
@override
FutureOr<String?> redirect(final BuildContext context, final GoRouterState state) {
final hasAccounts = NeonProvider.of<AccountsBloc>(context).hasAccounts;
if (state.fullPath == location && hasAccounts) {
return const _AddAccountQrcodeRoute().location;
return const _AddAccountQRcodeRoute().location;
}
return null;
@ -325,8 +325,8 @@ class _AddAccountFlowRoute extends LoginFlowRoute {
}
@immutable
class _AddAccountQrcodeRoute extends LoginQrcodeRoute {
const _AddAccountQrcodeRoute();
class _AddAccountQRcodeRoute extends LoginQRcodeRoute {
const _AddAccountQRcodeRoute();
}
@immutable

26
packages/neon/neon/lib/src/router.g.dart

@ -36,8 +36,8 @@ RouteBase get $homeRoute => GoRouteData.$route(
factory: $_AddAccountFlowRouteExtension._fromState,
),
GoRouteData.$route(
path: 'qrcode',
factory: $_AddAccountQrcodeRouteExtension._fromState,
path: 'qr-code',
factory: $_AddAccountQRcodeRouteExtension._fromState,
),
GoRouteData.$route(
path: 'check/server',
@ -50,7 +50,7 @@ RouteBase get $homeRoute => GoRouteData.$route(
],
),
GoRouteData.$route(
path: 'account/:accountid',
path: 'account/:accountID',
name: 'AccountSettings',
factory: $AccountSettingsRouteExtension._fromState,
),
@ -163,11 +163,11 @@ extension $_AddAccountFlowRouteExtension on _AddAccountFlowRoute {
void replace(BuildContext context) => context.replace(location);
}
extension $_AddAccountQrcodeRouteExtension on _AddAccountQrcodeRoute {
static _AddAccountQrcodeRoute _fromState(GoRouterState state) => const _AddAccountQrcodeRoute();
extension $_AddAccountQRcodeRouteExtension on _AddAccountQRcodeRoute {
static _AddAccountQRcodeRoute _fromState(GoRouterState state) => const _AddAccountQRcodeRoute();
String get location => GoRouteData.$location(
'/settings/account/add/qrcode',
'/settings/account/add/qr-code',
);
void go(BuildContext context) => context.go(location);
@ -227,11 +227,11 @@ extension $_AddAccountCheckAccountRouteExtension on _AddAccountCheckAccountRoute
extension $AccountSettingsRouteExtension on AccountSettingsRoute {
static AccountSettingsRoute _fromState(GoRouterState state) => AccountSettingsRoute(
accountid: state.pathParameters['accountid']!,
accountID: state.pathParameters['accountID']!,
);
String get location => GoRouteData.$location(
'/settings/account/${Uri.encodeComponent(accountid)}',
'/settings/account/${Uri.encodeComponent(accountID)}',
);
void go(BuildContext context) => context.go(location);
@ -266,8 +266,8 @@ RouteBase get $loginRoute => GoRouteData.$route(
factory: $LoginFlowRouteExtension._fromState,
),
GoRouteData.$route(
path: 'qrcode',
factory: $LoginQrcodeRouteExtension._fromState,
path: 'qr-code',
factory: $LoginQRcodeRouteExtension._fromState,
),
GoRouteData.$route(
path: 'check/server',
@ -317,11 +317,11 @@ extension $LoginFlowRouteExtension on LoginFlowRoute {
void replace(BuildContext context) => context.replace(location);
}
extension $LoginQrcodeRouteExtension on LoginQrcodeRoute {
static LoginQrcodeRoute _fromState(GoRouterState state) => const LoginQrcodeRoute();
extension $LoginQRcodeRouteExtension on LoginQRcodeRoute {
static LoginQRcodeRoute _fromState(GoRouterState state) => const LoginQRcodeRoute();
String get location => GoRouteData.$location(
'/login/qrcode',
'/login/qr-code',
);
void go(BuildContext context) => context.go(location);

4
packages/neon/neon/lib/src/theme/colors.dart

@ -31,12 +31,12 @@ abstract final class NcColors {
/// Color of a starred item.
static const Color starredColor = Colors.yellow;
/// Color used to emphasise declining actions.
/// Color used to emphasize declining actions.
///
/// Usually used in conjunction with [NcColors.accept].
static const Color decline = Colors.red;
/// Color used to emphasise accepting actions.
/// Color used to emphasize accepting actions.
///
/// Usually used in conjunction with [NcColors.decline].
static const Color accept = Colors.green;

2
packages/neon/neon/lib/src/utils/exceptions.dart

@ -8,4 +8,4 @@ class MissingPermissionException implements Exception {
class UnableToOpenFileException implements Exception {}
class InvalidQrcodeException implements Exception {}
class InvalidQRcodeException implements Exception {}

8
packages/neon/neon/lib/src/utils/global_options.dart

@ -174,14 +174,14 @@ class GlobalOptions extends OptionsCollection {
late final systemTrayEnabled = ToggleOption(
storage: storage,
key: GlobalOptionKeys.systemtrayEnabled,
key: GlobalOptionKeys.systemTrayEnabled,
label: (final context) => AppLocalizations.of(context).globalOptionsSystemTrayEnabled,
defaultValue: false,
);
late final systemTrayHideToTrayWhenMinimized = ToggleOption.depend(
storage: storage,
key: GlobalOptionKeys.systemtrayHideToTrayWhenMinimized,
key: GlobalOptionKeys.systemTrayHideToTrayWhenMinimized,
label: (final context) => AppLocalizations.of(context).globalOptionsSystemTrayHideToTrayWhenMinimized,
defaultValue: true,
enabled: systemTrayEnabled,
@ -228,8 +228,8 @@ enum GlobalOptionKeys implements Storable {
pushNotificationsDistributor._('push-notifications-distributor'),
startupMinimized._('startup-minimized'),
startupMinimizeInsteadOfExit._('startup-minimize-instead-of-exit'),
systemtrayEnabled._('systemtray-enabled'),
systemtrayHideToTrayWhenMinimized._('systemtray-hide-to-tray-when-minimized'),
systemTrayEnabled._('system-tray-enabled'),
systemTrayHideToTrayWhenMinimized._('system-tray-hide-to-tray-when-minimized'),
rememberLastUsedAccount._('remember-last-used-account'),
initialAccount._('initial-account'),
navigationMode._('navigation-mode');

2
packages/neon/neon/lib/src/utils/relative_time.dart

@ -1,6 +1,6 @@
import 'package:meta/meta.dart';
/// Extension for formating the differnce between two [DateTime]s.
/// Extension for formatting the difference between two [DateTime]s.
@internal
extension RelativeTimeFormat on DateTime {
/// Format the relative time between this and [to].

8
packages/neon/neon/lib/src/widgets/drawer_destination.dart

@ -50,7 +50,7 @@ extension NavigationRailDestinationExtension on NavigationRailDestination {
return icon;
}
final notificationIdicator = Builder(
final notificationIndicator = Builder(
builder: (final context) {
final style = TextStyle(
color: Theme.of(context).colorScheme.primary,
@ -68,7 +68,7 @@ extension NavigationRailDestinationExtension on NavigationRailDestination {
alignment: Alignment.bottomRight,
children: [
icon,
notificationIdicator,
notificationIndicator,
],
);
},
@ -95,7 +95,7 @@ extension NavigationDrawerDestinationExtension on NavigationDrawerDestination {
return label;
}
final notificationIdicator = Padding(
final notificationIndicator = Padding(
padding: const EdgeInsets.only(left: 12, right: 24),
child: Builder(
builder: (final context) {
@ -118,7 +118,7 @@ extension NavigationDrawerDestinationExtension on NavigationDrawerDestination {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
label,
notificationIdicator,
notificationIndicator,
],
),
);

4
packages/neon/neon/lib/src/widgets/exception.dart

@ -130,9 +130,9 @@ class NeonException extends StatelessWidget {
);
}
if (exception is InvalidQrcodeException) {
if (exception is InvalidQRcodeException) {
return ExceptionDetails(
text: AppLocalizations.of(context).errorInvalidQrcode,
text: AppLocalizations.of(context).errorInvalidQRcode,
);
}

12
packages/neon/neon/test/account_test.dart

@ -2,20 +2,20 @@ import 'package:neon/src/models/account.dart';
import 'package:test/test.dart';
void main() {
group('LoginQrcode', () {
group('LoginQRcode', () {
const qrCodePath = '/user:JohnDoe&password:super_secret&server:example.com';
const qrCode = 'nc://login$qrCodePath';
const invalidUrl = '::Not valid LoginQrcode::';
final credentials = LoginQrcode(
const invalidUrl = '::Not valid LoginQRcode::';
final credentials = LoginQRcode(
serverURL: Uri.parse('example.com'),
username: 'JohnDoe',
password: 'super_secret',
);
test('parse', () {
expect(LoginQrcode.tryParse(qrCode), equals(credentials));
expect(LoginQrcode.tryParse(qrCodePath), equals(credentials));
expect(LoginQrcode.tryParse(invalidUrl), null);
expect(LoginQRcode.tryParse(qrCode), equals(credentials));
expect(LoginQRcode.tryParse(qrCodePath), equals(credentials));
expect(LoginQRcode.tryParse(invalidUrl), null);
});
test('equality', () {

2
packages/neon/neon/test/result_test.dart

@ -25,7 +25,7 @@ void main() {
expect(a, equals(b), reason: 'ignore cached state in equality');
expect(a.hashCode, equals(a.hashCode), reason: 'identical');
expect(a.hashCode, isNot(equals(b.hashCode)), reason: 'hashcode should respect the cached state');
expect(a.hashCode, isNot(equals(b.hashCode)), reason: 'hashCode should respect the cached state');
});
test('Transform to loading', () {

1
packages/neon/neon_news/lib/blocs/news.dart

@ -105,7 +105,6 @@ class NewsBloc extends InteractiveBloc implements NewsBlocEvents, NewsBlocStates
feeds,
() async => account.client.news.listFeeds(),
(final response) {
// This is a bit ugly, but IDGAF right now
if (response.newestItemId != null) {
_newestItemId = response.newestItemId!;
}

2
packages/nextcloud/lib/src/api/notifications.openapi.json

@ -729,7 +729,7 @@
],
"responses": {
"200": {
"description": "Existing nsotification IDs returned",
"description": "Existing notification IDs returned",
"content": {
"application/json": {
"schema": {

2
packages/nextcloud/lib/src/webdav/file.dart

@ -80,7 +80,7 @@ class WebDavFile {
/// Returns the decoded name of the file / folder without the whole path
late final String name = () {
// normalised path (remove trailing slash)
// normalized path (remove trailing slash)
final end = path.endsWith('/') ? path.length - 1 : path.length;
final segments = Uri.parse(path, 0, end).pathSegments;

8
tool/update-cspell-dictionaries.sh

@ -0,0 +1,8 @@
#!/bin/bash
set -euxo pipefail
cd "$(dirname "$0")/.."
for file in .cspell/*; do
rm "$file"
cspell lint --quiet --unique --words-only . | tr '[:upper:]' '[:lower:]' | sort -f | uniq > "$file" || true
done
Loading…
Cancel
Save