diff --git a/packages/app/integration_test/screenshot_test.dart b/packages/app/integration_test/screenshot_test.dart index 14bec1f1..7ad759e4 100644 --- a/packages/app/integration_test/screenshot_test.dart +++ b/packages/app/integration_test/screenshot_test.dart @@ -9,85 +9,11 @@ import 'package:integration_test/integration_test.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:neon/models.dart'; import 'package:neon/neon.dart'; +import 'package:neon/nextcloud.dart'; +import 'package:neon/settings.dart'; import 'package:neon_files/widgets/actions.dart'; import 'package:shared_preferences/shared_preferences.dart'; -class MemorySharedPreferences implements SharedPreferences { - final _data = {}; - - @override - Future clear() async { - _data.clear(); - return true; - } - - @override - Future commit() async => true; - - @override - Future reload() async {} - - @override - Future remove(final String key) async { - _data.remove(key); - return true; - } - - @override - Set getKeys() => _data.keys.toSet(); - - @override - bool containsKey(final String key) => _data.keys.contains(key); - - @override - Object? get(final String key) => _data[key]; - - @override - bool? getBool(final String key) => _data[key] as bool?; - - @override - double? getDouble(final String key) => _data[key] as double?; - - @override - int? getInt(final String key) => _data[key] as int?; - - @override - String? getString(final String key) => _data[key] as String?; - - @override - List? getStringList(final String key) => (_data[key] as List).cast(); - - @override - Future setBool(final String key, final bool value) async { - _data[key] = value; - return true; - } - - @override - Future setDouble(final String key, final double value) async { - _data[key] = value; - return true; - } - - @override - Future setInt(final String key, final int value) async { - _data[key] = value; - return true; - } - - @override - Future setString(final String key, final String value) async { - _data[key] = value; - return true; - } - - @override - Future setStringList(final String key, final List value) async { - _data[key] = value; - return true; - } -} - Future runTestApp( final WidgetTester tester, final IntegrationTestWidgetsFlutterBinding binding, { @@ -97,7 +23,6 @@ Future runTestApp( getAppImplementations: getAppImplementations, theme: neonTheme, bindingOverride: binding, - sharedPreferencesOverride: MemorySharedPreferences(), account: account, firstLaunchDisabled: true, nextPushDisabled: true, @@ -112,7 +37,7 @@ Future openDrawer(final WidgetTester tester) async { Future switchPage(final WidgetTester tester, final String name) async { await openDrawer(tester); - await tester.tap(find.byKey(Key(name))); + await tester.tap(find.text(name).last); await tester.pumpAndSettle(); } @@ -121,22 +46,41 @@ Future prepareScreenshot(final WidgetTester tester, final IntegrationTestWidgets await tester.pumpAndSettle(); } +Future getAccount(final String username) async { + const host = 'http://10.0.2.2'; + final appPassword = (await NextcloudClient( + host, + loginName: username, + password: username, + ).core.appPassword.getAppPassword()) + .ocs + .data + .apppassword; + return Account( + serverURL: host, + username: username, + password: appPassword, + ); +} + Future main() async { // The screenshots are pretty annoying on Android. See https://github.com/flutter/flutter/issues/92381 assert(Platform.isAndroid, 'Screenshots need to be taken on Android'); final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - final account = Account( - serverURL: 'http://10.0.2.2', - username: 'user1', - password: 'user1', - ); + + late Account account; setUpAll(() async { + account = await getAccount('demo'); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); }); + setUp(() { + SharedPreferences.setMockInitialValues({}); + }); + testWidgets('login', (final tester) async { await runTestApp( tester, @@ -144,14 +88,6 @@ Future main() async { ); await prepareScreenshot(tester, binding); await binding.takeScreenshot('login_server_selection'); - - await tester.enterText(find.byType(TextFormField), account.serverURL); - await tester.pumpAndSettle(); - await tester.testTextInput.receiveAction(TextInputAction.done); - await tester.pumpAndSettle(); - await tester.pump(const Duration(seconds: 3)); // Make sure the login webview is loaded - await tester.pumpAndSettle(); - await binding.takeScreenshot('login_form'); }); testWidgets('home', (final tester) async { @@ -222,7 +158,7 @@ Future main() async { account: account, ); await prepareScreenshot(tester, binding); - await switchPage(tester, 'app-news'); + await switchPage(tester, 'News'); // Show folders await tester.tap(find.byIcon(Icons.folder)); @@ -292,7 +228,7 @@ Future main() async { account: account, ); await prepareScreenshot(tester, binding); - await switchPage(tester, 'app-notes'); + await switchPage(tester, 'Notes'); // Create note await tester.tap(find.byType(FloatingActionButton)); @@ -343,11 +279,7 @@ Future main() async { }); testWidgets('notifications', (final tester) async { - await Account( - serverURL: 'http://10.0.2.2', - username: 'admin', - password: 'admin', - ).client.notifications.sendAdminNotification( + await (await getAccount('admin')).client.notifications.sendAdminNotification( userId: account.username, shortMessage: 'Notifications demo', longMessage: 'This is a notifications demo of the Neon app', @@ -359,7 +291,7 @@ Future main() async { account: account, ); await prepareScreenshot(tester, binding); - await tester.tap(find.byKey(const Key('app-notifications'))); + await tester.tap(find.byTooltip('Notifications')); await tester.pumpAndSettle(); await tester.pumpAndSettle(); @@ -375,7 +307,7 @@ Future main() async { account: account, ); await prepareScreenshot(tester, binding); - await switchPage(tester, 'settings'); + await switchPage(tester, 'Settings'); // Open Files settings await tester.tap(find.text('Files')); @@ -426,13 +358,13 @@ Future main() async { await tester.pumpAndSettle(); // Scroll down to accounts - await tester.drag(find.byType(ListView), const Offset(0, -10000)); + await tester.drag(find.byType(SettingsList).first, const Offset(0, -10000)); await tester.pumpAndSettle(); await binding.takeScreenshot('settings_accounts'); // Go to account settings - await tester.tap(find.text('user1@10.0.2.2:80')); + await tester.tap(find.text('demo@10.0.2.2:80')); await tester.pumpAndSettle(); await tester.tap(find.text('Automatic')); await tester.pumpAndSettle(); diff --git a/packages/app/screenshots/files_actions.png b/packages/app/screenshots/files_actions.png index 78672ba9..41de936c 100644 Binary files a/packages/app/screenshots/files_actions.png and b/packages/app/screenshots/files_actions.png differ diff --git a/packages/app/screenshots/files_create.png b/packages/app/screenshots/files_create.png index e3a30fac..fdaee11a 100644 Binary files a/packages/app/screenshots/files_create.png and b/packages/app/screenshots/files_create.png differ diff --git a/packages/app/screenshots/files_details.png b/packages/app/screenshots/files_details.png index 43a9972e..0d4a0d6a 100644 Binary files a/packages/app/screenshots/files_details.png and b/packages/app/screenshots/files_details.png differ diff --git a/packages/app/screenshots/files_photos.png b/packages/app/screenshots/files_photos.png index 6a740e53..c5c79bfd 100644 Binary files a/packages/app/screenshots/files_photos.png and b/packages/app/screenshots/files_photos.png differ diff --git a/packages/app/screenshots/files_root.png b/packages/app/screenshots/files_root.png index 142f8717..d2f5edd1 100644 Binary files a/packages/app/screenshots/files_root.png and b/packages/app/screenshots/files_root.png differ diff --git a/packages/app/screenshots/home_drawer.png b/packages/app/screenshots/home_drawer.png index 83d3fbdd..51deb3c4 100644 Binary files a/packages/app/screenshots/home_drawer.png and b/packages/app/screenshots/home_drawer.png differ diff --git a/packages/app/screenshots/login_form.png b/packages/app/screenshots/login_form.png deleted file mode 100644 index cfb61c24..00000000 Binary files a/packages/app/screenshots/login_form.png and /dev/null differ diff --git a/packages/app/screenshots/login_server_selection.png b/packages/app/screenshots/login_server_selection.png index 290c9799..9fc57057 100644 Binary files a/packages/app/screenshots/login_server_selection.png and b/packages/app/screenshots/login_server_selection.png differ diff --git a/packages/app/screenshots/news_articles_starred_list.png b/packages/app/screenshots/news_articles_starred_list.png index a42d3089..80e0fbc5 100644 Binary files a/packages/app/screenshots/news_articles_starred_list.png and b/packages/app/screenshots/news_articles_starred_list.png differ diff --git a/packages/app/screenshots/news_articles_unread_list.png b/packages/app/screenshots/news_articles_unread_list.png index da6e4073..828df2dd 100644 Binary files a/packages/app/screenshots/news_articles_unread_list.png and b/packages/app/screenshots/news_articles_unread_list.png differ diff --git a/packages/app/screenshots/news_feed_add.png b/packages/app/screenshots/news_feed_add.png index 8665bb45..9283c682 100644 Binary files a/packages/app/screenshots/news_feed_add.png and b/packages/app/screenshots/news_feed_add.png differ diff --git a/packages/app/screenshots/news_feed_articles_list.png b/packages/app/screenshots/news_feed_articles_list.png index f6f2f736..4ef59ebc 100644 Binary files a/packages/app/screenshots/news_feed_articles_list.png and b/packages/app/screenshots/news_feed_articles_list.png differ diff --git a/packages/app/screenshots/news_feeds_list.png b/packages/app/screenshots/news_feeds_list.png index abe354d1..450c6163 100644 Binary files a/packages/app/screenshots/news_feeds_list.png and b/packages/app/screenshots/news_feeds_list.png differ diff --git a/packages/app/screenshots/news_folders_list.png b/packages/app/screenshots/news_folders_list.png index 60e05626..968c33d2 100644 Binary files a/packages/app/screenshots/news_folders_list.png and b/packages/app/screenshots/news_folders_list.png differ diff --git a/packages/app/screenshots/notes_categories_list.png b/packages/app/screenshots/notes_categories_list.png index ccba8e6f..d658b35c 100644 Binary files a/packages/app/screenshots/notes_categories_list.png and b/packages/app/screenshots/notes_categories_list.png differ diff --git a/packages/app/screenshots/notes_note_create.png b/packages/app/screenshots/notes_note_create.png index ee8fcb1f..ad3cb49f 100644 Binary files a/packages/app/screenshots/notes_note_create.png and b/packages/app/screenshots/notes_note_create.png differ diff --git a/packages/app/screenshots/notes_note_edit.png b/packages/app/screenshots/notes_note_edit.png index 4f3548c8..0b64cb84 100644 Binary files a/packages/app/screenshots/notes_note_edit.png and b/packages/app/screenshots/notes_note_edit.png differ diff --git a/packages/app/screenshots/notes_note_preview.png b/packages/app/screenshots/notes_note_preview.png index 3884e0a0..ab174a9d 100644 Binary files a/packages/app/screenshots/notes_note_preview.png and b/packages/app/screenshots/notes_note_preview.png differ diff --git a/packages/app/screenshots/notes_notes_list.png b/packages/app/screenshots/notes_notes_list.png index 05a8a5b1..f6e14ee0 100644 Binary files a/packages/app/screenshots/notes_notes_list.png and b/packages/app/screenshots/notes_notes_list.png differ diff --git a/packages/app/screenshots/notifications_list.png b/packages/app/screenshots/notifications_list.png index 70afbc7f..10748c13 100644 Binary files a/packages/app/screenshots/notifications_list.png and b/packages/app/screenshots/notifications_list.png differ diff --git a/packages/app/screenshots/settings_account.png b/packages/app/screenshots/settings_account.png index 0a302d6b..5978217f 100644 Binary files a/packages/app/screenshots/settings_account.png and b/packages/app/screenshots/settings_account.png differ diff --git a/packages/app/screenshots/settings_accounts.png b/packages/app/screenshots/settings_accounts.png index 1bfda139..83e9ec20 100644 Binary files a/packages/app/screenshots/settings_accounts.png and b/packages/app/screenshots/settings_accounts.png differ diff --git a/packages/app/screenshots/settings_app_files.png b/packages/app/screenshots/settings_app_files.png index 77929153..e1ce724f 100644 Binary files a/packages/app/screenshots/settings_app_files.png and b/packages/app/screenshots/settings_app_files.png differ diff --git a/packages/app/screenshots/settings_app_news.png b/packages/app/screenshots/settings_app_news.png index 584c3fa8..751798e6 100644 Binary files a/packages/app/screenshots/settings_app_news.png and b/packages/app/screenshots/settings_app_news.png differ diff --git a/packages/app/screenshots/settings_app_notes.png b/packages/app/screenshots/settings_app_notes.png index eb9d9c4f..6a5acf34 100644 Binary files a/packages/app/screenshots/settings_app_notes.png and b/packages/app/screenshots/settings_app_notes.png differ diff --git a/packages/app/screenshots/settings_dark.png b/packages/app/screenshots/settings_dark.png index e7e43c77..01fafc7c 100644 Binary files a/packages/app/screenshots/settings_dark.png and b/packages/app/screenshots/settings_dark.png differ diff --git a/packages/app/screenshots/settings_light.png b/packages/app/screenshots/settings_light.png index 77cacf0b..81399d3e 100644 Binary files a/packages/app/screenshots/settings_light.png and b/packages/app/screenshots/settings_light.png differ diff --git a/packages/app/screenshots/settings_oled.png b/packages/app/screenshots/settings_oled.png index 7959e088..a8d6f2fd 100644 Binary files a/packages/app/screenshots/settings_oled.png and b/packages/app/screenshots/settings_oled.png differ diff --git a/packages/app/test_driver/integration_test.dart b/packages/app/test_driver/integration_test.dart index 02b2879d..dfa7edae 100644 --- a/packages/app/test_driver/integration_test.dart +++ b/packages/app/test_driver/integration_test.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:flutter/foundation.dart'; import 'package:integration_test/integration_test_driver_extended.dart'; Future main() async { @@ -16,6 +15,7 @@ Future main() async { }, ); } catch (e) { - debugPrint('Error occurred: $e'); + // ignore: avoid_print + print('Error occurred: $e'); } } diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index 7ce1372c..9d01e322 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; -import 'package:meta/meta.dart'; import 'package:neon/src/app.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/blocs/first_launch.dart'; @@ -14,27 +13,24 @@ import 'package:neon/src/platform/platform.dart'; import 'package:neon/src/theme/neon.dart'; import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/request_manager.dart'; +import 'package:neon/src/utils/user_agent.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; -@internal -late final String neonUserAgent; - Future runNeon({ required final Iterable Function(SharedPreferences, RequestManager, NeonPlatform) getAppImplementations, required final NeonTheme theme, - final WidgetsBinding? bindingOverride, - final SharedPreferences? sharedPreferencesOverride, - final Account? account, - final bool firstLaunchDisabled = false, - final bool nextPushDisabled = false, + @visibleForTesting final WidgetsBinding? bindingOverride, + @visibleForTesting final Account? account, + @visibleForTesting final bool firstLaunchDisabled = false, + @visibleForTesting final bool nextPushDisabled = false, }) async { final binding = bindingOverride ?? WidgetsFlutterBinding.ensureInitialized(); FlutterNativeSplash.preserve(widgetsBinding: binding); - final sharedPreferences = sharedPreferencesOverride ?? await SharedPreferences.getInstance(); + final sharedPreferences = await SharedPreferences.getInstance(); final platform = await getNeonPlatform(); final cache = Cache(platform); @@ -43,11 +39,7 @@ Future runNeon({ final allAppImplementations = getAppImplementations(sharedPreferences, requestManager, platform); final packageInfo = await PackageInfo.fromPlatform(); - var buildNumber = packageInfo.buildNumber; - if (buildNumber.isEmpty) { - buildNumber = '1'; - } - neonUserAgent = 'Neon ${packageInfo.version}+$buildNumber'; + buildUserAgent(packageInfo); final globalOptions = GlobalOptions( sharedPreferences, diff --git a/packages/neon/neon/lib/settings.dart b/packages/neon/neon/lib/settings.dart index 15823bf3..08c0053e 100644 --- a/packages/neon/neon/lib/settings.dart +++ b/packages/neon/neon/lib/settings.dart @@ -4,3 +4,4 @@ export 'package:neon/src/settings/models/options_category.dart'; export 'package:neon/src/settings/models/select_option.dart'; export 'package:neon/src/settings/models/storage.dart'; export 'package:neon/src/settings/models/toggle_option.dart'; +export 'package:neon/src/settings/widgets/settings_list.dart'; diff --git a/packages/neon/neon/lib/src/blocs/login_check_account.dart b/packages/neon/neon/lib/src/blocs/login_check_account.dart index 5608dd0a..3fcc2be0 100644 --- a/packages/neon/neon/lib/src/blocs/login_check_account.dart +++ b/packages/neon/neon/lib/src/blocs/login_check_account.dart @@ -1,10 +1,10 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; -import 'package:neon/neon.dart'; import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/result.dart'; import 'package:neon/src/models/account.dart'; +import 'package:neon/src/utils/user_agent.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:rxdart/rxdart.dart'; diff --git a/packages/neon/neon/lib/src/blocs/login_check_server_status.dart b/packages/neon/neon/lib/src/blocs/login_check_server_status.dart index 5a4877e6..81acbd08 100644 --- a/packages/neon/neon/lib/src/blocs/login_check_server_status.dart +++ b/packages/neon/neon/lib/src/blocs/login_check_server_status.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; -import 'package:neon/neon.dart'; import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/result.dart'; +import 'package:neon/src/utils/user_agent.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:rxdart/rxdart.dart'; diff --git a/packages/neon/neon/lib/src/blocs/login_flow.dart b/packages/neon/neon/lib/src/blocs/login_flow.dart index 18426321..374478af 100644 --- a/packages/neon/neon/lib/src/blocs/login_flow.dart +++ b/packages/neon/neon/lib/src/blocs/login_flow.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; -import 'package:neon/neon.dart'; import 'package:neon/src/bloc/bloc.dart'; import 'package:neon/src/bloc/result.dart'; +import 'package:neon/src/utils/user_agent.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:rxdart/rxdart.dart'; diff --git a/packages/neon/neon/lib/src/settings/widgets/settings_list.dart b/packages/neon/neon/lib/src/settings/widgets/settings_list.dart index fb609dd7..55642062 100644 --- a/packages/neon/neon/lib/src/settings/widgets/settings_list.dart +++ b/packages/neon/neon/lib/src/settings/widgets/settings_list.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:meta/meta.dart'; import 'package:neon/src/settings/widgets/settings_category.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; -@internal +@visibleForTesting class SettingsList extends StatelessWidget { const SettingsList({ required this.categories, diff --git a/packages/neon/neon/lib/src/utils/user_agent.dart b/packages/neon/neon/lib/src/utils/user_agent.dart new file mode 100644 index 00000000..4612edcc --- /dev/null +++ b/packages/neon/neon/lib/src/utils/user_agent.dart @@ -0,0 +1,15 @@ +import 'package:meta/meta.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +late String? _userAgent; + +void buildUserAgent(final PackageInfo packageInfo) { + var buildNumber = packageInfo.buildNumber; + if (buildNumber.isEmpty) { + buildNumber = '1'; + } + _userAgent = 'Neon ${packageInfo.version}+$buildNumber'; +} + +@internal +String get neonUserAgent => _userAgent!; diff --git a/tool/Dockerfile.dev b/tool/Dockerfile.dev index 9223e626..ce5f703c 100644 --- a/tool/Dockerfile.dev +++ b/tool/Dockerfile.dev @@ -10,6 +10,7 @@ RUN ./occ app:disable password_policy RUN OC_PASS="user1" ./occ user:add --password-from-env --display-name "User One" user1 RUN OC_PASS="user2" ./occ user:add --password-from-env --display-name "User Two" user2 +RUN OC_PASS="demo" ./occ user:add --password-from-env --display-name "Demo" demo RUN ./occ app:install news --force --allow-unstable # 21.2.0 RUN ./occ app:install notes --force --allow-unstable # 4.8.0 @@ -18,5 +19,6 @@ RUN ./occ app:install uppush --force --allow-unstable # 1.4.0 RUN ./occ app:enable password_policy RUN (sh /entrypoint.sh php -S 0.0.0.0:8080 &) && \ until curl -s -o /dev/null http://localhost:8080/status.php; do true; done && \ + # Do not setup the demo user here for user in admin user1 user2; do curl -u "$user:$user" -H "ocs-apirequest: true" -s -o /dev/null http://localhost:8080/ocs/v2.php/cloud/user; done COPY --chown=www-data:www-data overlay /usr/src/nextcloud/