diff --git a/packages/neon/assets/.gitignore b/packages/neon/assets/.gitignore deleted file mode 100644 index 4c49bd78..00000000 --- a/packages/neon/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.env diff --git a/packages/neon/integration_test/screenshot_test.dart b/packages/neon/integration_test/screenshot_test.dart index c6ff344c..fc1b4485 100644 --- a/packages/neon/integration_test/screenshot_test.dart +++ b/packages/neon/integration_test/screenshot_test.dart @@ -147,9 +147,6 @@ Future pumpAppPage( Provider( create: (final _) => sharedPreferences, ), - Provider( - create: (final _) => null, - ), Provider( create: (final _) => platform, ), diff --git a/packages/neon/lib/main.dart b/packages/neon/lib/main.dart index aa848470..2bbd9c50 100644 --- a/packages/neon/lib/main.dart +++ b/packages/neon/lib/main.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:neon/src/neon.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -8,19 +6,6 @@ import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; Future main() async { - Env? env; - try { - await dotenv.load(fileName: 'assets/.env'); - if (dotenv.env.keys.isNotEmpty) { - if (kReleaseMode) { - throw Exception('A release build can not contain a .env file'); - } - env = Env.fromMap(dotenv.env); - } - } catch (e) { - debugPrint('Failed to load env: $e'); - } - WidgetsFlutterBinding.ensureInitialized(); FlutterNativeSplash.preserve(widgetsBinding: WidgetsBinding.instance); @@ -63,9 +48,6 @@ Future main() async { Provider( create: (final _) => sharedPreferences, ), - Provider( - create: (final _) => env, - ), Provider( create: (final _) => platform, ), @@ -97,7 +79,6 @@ Future main() async { child: NeonApp( accountsBloc: accountsBloc, sharedPreferences: sharedPreferences, - env: env, platform: platform, globalOptions: globalOptions, ), diff --git a/packages/neon/lib/src/app.dart b/packages/neon/lib/src/app.dart index 51f70b21..7fd4fff5 100644 --- a/packages/neon/lib/src/app.dart +++ b/packages/neon/lib/src/app.dart @@ -4,7 +4,6 @@ class NeonApp extends StatefulWidget { const NeonApp({ required this.accountsBloc, required this.sharedPreferences, - required this.env, required this.platform, required this.globalOptions, super.key, @@ -12,7 +11,6 @@ class NeonApp extends StatefulWidget { final AccountsBloc accountsBloc; final SharedPreferences sharedPreferences; - final Env? env; final NeonPlatform platform; final GlobalOptions globalOptions; diff --git a/packages/neon/lib/src/neon.dart b/packages/neon/lib/src/neon.dart index e6c9e37f..58f96fb0 100644 --- a/packages/neon/lib/src/neon.dart +++ b/packages/neon/lib/src/neon.dart @@ -69,7 +69,6 @@ part 'utils/account_options.dart'; part 'utils/app_implementation.dart'; part 'utils/bloc.dart'; part 'utils/confirmation_dialog.dart'; -part 'utils/env.dart'; part 'utils/global.dart'; part 'utils/global_options.dart'; part 'utils/global_popups.dart'; diff --git a/packages/neon/lib/src/pages/login.dart b/packages/neon/lib/src/pages/login.dart index c2f1dd9f..0f31a741 100644 --- a/packages/neon/lib/src/pages/login.dart +++ b/packages/neon/lib/src/pages/login.dart @@ -38,9 +38,6 @@ class _LoginPageState extends State { await launchUrlString( init.login, mode: LaunchMode.externalApplication, - webViewConfiguration: WebViewConfiguration( - headers: _buildHeaders(context, Provider.of(context, listen: false)), - ), ); }); } @@ -85,18 +82,6 @@ class _LoginPageState extends State { }); } - Map _buildHeaders( - final BuildContext context, - final Env? env, - ) => - { - HttpHeaders.userAgentHeader: userAgent(_packageInfo), - if (env != null) ...{ - HttpHeaders.authorizationHeader: - 'Basic ${base64.encode(utf8.encode('${env.testUsername}:${env.testPassword}'))}', - }, - }; - @override void dispose() { _loginBloc.dispose(); @@ -104,151 +89,143 @@ class _LoginPageState extends State { } @override - Widget build(final BuildContext context) { - final env = Provider.of(context); - - return StreamBuilder>( - stream: _accountsBloc.accounts, - builder: (final context, final accountsSnapshot) => WillPopScope( - onWillPop: () async { - if (accountsSnapshot.data?.isNotEmpty ?? false) { - return true; - } + Widget build(final BuildContext context) => StreamBuilder>( + stream: _accountsBloc.accounts, + builder: (final context, final accountsSnapshot) => WillPopScope( + onWillPop: () async { + if (accountsSnapshot.data?.isNotEmpty ?? false) { + return true; + } - if ((await _loginBloc.serverURL.first) == null) { - return true; - } + if ((await _loginBloc.serverURL.first) == null) { + return true; + } - _loginBloc.setServerURL(null); - return false; - }, - child: StreamBuilder( - stream: _loginBloc.serverURL, - builder: (final context, final serverURLSnapshot) => StreamBuilder( - stream: _loginBloc.serverConnectionState, - builder: (final context, final serverConnectionStateSnapshot) => Scaffold( - appBar: serverConnectionStateSnapshot.data == ServerConnectionState.success || - (accountsSnapshot.data?.isNotEmpty ?? false) - ? AppBar( - leading: IconButton( - onPressed: () { - if (accountsSnapshot.data?.isNotEmpty ?? false) { - Navigator.of(context).pop(); - } else { - _loginBloc.setServerURL(null); - } - }, - icon: const Icon(Icons.arrow_back), - ), - actions: [ - if (serverConnectionStateSnapshot.data != null) ...[ - IconButton( - onPressed: _loginBloc.refresh, - icon: const Icon(Icons.refresh), - ), - ], - ], - ) - : null, - body: serverConnectionStateSnapshot.data == ServerConnectionState.success - ? Provider.of(context).canUseWebView - ? WebView( - javascriptMode: JavascriptMode.unrestricted, - zoomEnabled: false, - userAgent: userAgent(_packageInfo), - onWebViewCreated: (final controller) async { - _webViewController = controller; - final url = - (await _loginBloc.loginFlowInit.firstWhere((final init) => init != null))!.login; - if (mounted) { - await _webViewController!.loadUrl( - url, - headers: _buildHeaders(context, env), - ); + _loginBloc.setServerURL(null); + return false; + }, + child: StreamBuilder( + stream: _loginBloc.serverURL, + builder: (final context, final serverURLSnapshot) => StreamBuilder( + stream: _loginBloc.serverConnectionState, + builder: (final context, final serverConnectionStateSnapshot) => Scaffold( + appBar: serverConnectionStateSnapshot.data == ServerConnectionState.success || + (accountsSnapshot.data?.isNotEmpty ?? false) + ? AppBar( + leading: IconButton( + onPressed: () { + if (accountsSnapshot.data?.isNotEmpty ?? false) { + Navigator.of(context).pop(); + } else { + _loginBloc.setServerURL(null); } }, - ) - : Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(AppLocalizations.of(context).loginSwitchToBrowserWindow), - const SizedBox( - height: 10, - ), - ElevatedButton( - onPressed: _loginBloc.refresh, - child: Text(AppLocalizations.of(context).loginOpenAgain), - ), - ], - ), - ) - : Center( - child: ListView( - shrinkWrap: true, - padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20), - children: [ - SizedBox( - height: MediaQuery.of(context).size.height / 2, + icon: const Icon(Icons.arrow_back), + ), + actions: [ + if (serverConnectionStateSnapshot.data != null) ...[ + IconButton( + onPressed: _loginBloc.refresh, + icon: const Icon(Icons.refresh), + ), + ], + ], + ) + : null, + body: serverConnectionStateSnapshot.data == ServerConnectionState.success + ? Provider.of(context).canUseWebView + ? WebView( + javascriptMode: JavascriptMode.unrestricted, + zoomEnabled: false, + userAgent: userAgent(_packageInfo), + onWebViewCreated: (final controller) async { + _webViewController = controller; + final url = + (await _loginBloc.loginFlowInit.firstWhere((final init) => init != null))!.login; + if (mounted) { + await _webViewController!.loadUrl(url); + } + }, + ) + : Center( child: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ - const NeonLogo(), + Text(AppLocalizations.of(context).loginSwitchToBrowserWindow), const SizedBox( - height: 30, + height: 10, ), - Text(AppLocalizations.of(context).loginWorksWith), - const SizedBox( - height: 20, + ElevatedButton( + onPressed: _loginBloc.refresh, + child: Text(AppLocalizations.of(context).loginOpenAgain), ), - const NextcloudLogo(), ], ), - ), - Form( - key: _formKey, - child: TextFormField( - focusNode: _focusNode, - decoration: const InputDecoration( - hintText: 'https://...', + ) + : Center( + child: ListView( + shrinkWrap: true, + padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20), + children: [ + SizedBox( + height: MediaQuery.of(context).size.height / 2, + child: Column( + children: [ + const NeonLogo(), + const SizedBox( + height: 30, + ), + Text(AppLocalizations.of(context).loginWorksWith), + const SizedBox( + height: 20, + ), + const NextcloudLogo(), + ], ), - initialValue: - widget.serverURL ?? (env?.testHost != null ? 'http://${env!.testHost}' : null), - validator: (final input) => validateHttpUrl(context, input), - onFieldSubmitted: (final input) { - if (_formKey.currentState!.validate()) { - _loginBloc.setServerURL(input); - } else { - _focusNode.requestFocus(); - } - }, ), - ), - Column( - children: [ - CustomLinearProgressIndicator( - visible: serverConnectionStateSnapshot.data == ServerConnectionState.loading, - ), - if (serverConnectionStateSnapshot.data == ServerConnectionState.unreachable) ...[ - ExceptionWidget( - AppLocalizations.of(context).errorUnableToReachServer, - onRetry: _loginBloc.refresh, + Form( + key: _formKey, + child: TextFormField( + focusNode: _focusNode, + decoration: const InputDecoration( + hintText: 'https://...', ), - ], - if (serverConnectionStateSnapshot.data == ServerConnectionState.maintenanceMode) ...[ - ExceptionWidget( - AppLocalizations.of(context).errorServerInMaintenanceMode, - onRetry: _loginBloc.refresh, + initialValue: widget.serverURL, + validator: (final input) => validateHttpUrl(context, input), + onFieldSubmitted: (final input) { + if (_formKey.currentState!.validate()) { + _loginBloc.setServerURL(input); + } else { + _focusNode.requestFocus(); + } + }, + ), + ), + Column( + children: [ + CustomLinearProgressIndicator( + visible: serverConnectionStateSnapshot.data == ServerConnectionState.loading, ), + if (serverConnectionStateSnapshot.data == ServerConnectionState.unreachable) ...[ + ExceptionWidget( + AppLocalizations.of(context).errorUnableToReachServer, + onRetry: _loginBloc.refresh, + ), + ], + if (serverConnectionStateSnapshot.data == ServerConnectionState.maintenanceMode) ...[ + ExceptionWidget( + AppLocalizations.of(context).errorServerInMaintenanceMode, + onRetry: _loginBloc.refresh, + ), + ], ], - ], - ), - ], + ), + ], + ), ), - ), + ), ), ), ), - ), - ); - } + ); } diff --git a/packages/neon/lib/src/utils/env.dart b/packages/neon/lib/src/utils/env.dart deleted file mode 100644 index 66c01878..00000000 --- a/packages/neon/lib/src/utils/env.dart +++ /dev/null @@ -1,19 +0,0 @@ -part of '../neon.dart'; - -class Env { - Env({ - this.testHost, - this.testUsername, - this.testPassword, - }); - - factory Env.fromMap(final Map data) => Env( - testHost: data['TEST_HOST'], - testUsername: data['TEST_USER'], - testPassword: data['TEST_PASSWORD'], - ); - - final String? testHost; - final String? testUsername; - final String? testPassword; -} diff --git a/packages/neon/pubspec.lock b/packages/neon/pubspec.lock index 5daff98d..65af0f11 100644 --- a/packages/neon/pubspec.lock +++ b/packages/neon/pubspec.lock @@ -293,14 +293,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.0" - flutter_dotenv: - dependency: "direct main" - description: - name: flutter_dotenv - sha256: d9283d92059a22e9834bc0a31336658ffba77089fb6f3cc36751f1fc7c6661a3 - url: "https://pub.dev" - source: hosted - version: "5.0.2" flutter_driver: dependency: transitive description: flutter diff --git a/packages/neon/pubspec.yaml b/packages/neon/pubspec.yaml index 581a7f35..d6ed6ab7 100644 --- a/packages/neon/pubspec.yaml +++ b/packages/neon/pubspec.yaml @@ -16,7 +16,6 @@ dependencies: flutter: sdk: flutter flutter_cache_manager: ^3.3.0 - flutter_dotenv: ^5.0.2 flutter_file_dialog: ^2.3.0 flutter_html: ^3.0.0-alpha.3 flutter_local_notifications: ^12.0.2 diff --git a/tool/build-dev-container-image.sh b/tool/build-dev-container.sh similarity index 100% rename from tool/build-dev-container-image.sh rename to tool/build-dev-container.sh diff --git a/tool/dev.sh b/tool/dev.sh new file mode 100755 index 00000000..f6ef40e5 --- /dev/null +++ b/tool/dev.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -euxo pipefail +cd "$(dirname "$0")/.." + +./tool/build-dev-container.sh + +echo "Running development instance on http://localhost. To access it in an Android Emulator use http://10.0.2.2" +docker run --rm -v nextcloud-neon-dev:/usr/src/nextcloud -v nextcloud-neon-dev:/var/www/html -p "80:80" --add-host host.docker.internal:host-gateway nextcloud-neon-dev diff --git a/tool/generate-screenshots.sh b/tool/generate-screenshots.sh index 92672b9a..16514e8e 100755 --- a/tool/generate-screenshots.sh +++ b/tool/generate-screenshots.sh @@ -2,7 +2,7 @@ set -euxo pipefail cd "$(dirname "$0")/.." -./tool/build-dev-container-image.sh +./tool/build-dev-container.sh container_id="$(docker run --rm -d -p "80:80" nextcloud-neon-dev)" function cleanup() { docker kill "$container_id" diff --git a/tool/run-dev-instance.sh b/tool/run-dev-instance.sh deleted file mode 100755 index e5222a6e..00000000 --- a/tool/run-dev-instance.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -set -euxo pipefail -cd "$(dirname "$0")/.." - -ip="" -if [ "$#" -ne 1 ]; then - echo "You need to give the platform type: localhost, android-emulator" - exit 1 -elif [[ "$1" == "android-emulator" ]]; then - ip="10.0.2.2" -elif [[ "$1" == "localhost" ]]; then - ip="localhost" -else - echo "Unknown platform type: $1" - exit 1 -fi - -./tool/build-dev-container-image.sh - -echo "TEST_HOST=$ip -TEST_USER=user1 -TEST_PASSWORD=user1" > packages/neon/assets/.env - -function cleanup() { - rm packages/neon/assets/.env -} -trap cleanup EXIT -docker run --rm -v nextcloud-neon-dev:/usr/src/nextcloud -v nextcloud-neon-dev:/var/www/html -p "80:80" --add-host host.docker.internal:host-gateway nextcloud-neon-dev