From 558a28d12b3b4d31d30bf9ab17f0c2c8d2491b87 Mon Sep 17 00:00:00 2001 From: Agboola Onasanya Date: Thu, 9 Apr 2026 15:47:59 +0100 Subject: [PATCH] . --- .gitignore | 34 +-- .metadata | 30 +-- assets/images/nextcloud_logo.png | Bin 0 -> 94420 bytes devtools_options.yaml | 3 + lib/api/login_api.dart | 29 -- lib/app/extension.dart | 19 ++ lib/app/login_flow.dart | 104 ++++++++ lib/app/nextcloud_app.dart | 51 ++++ lib/components/default_values.dart | 54 ---- lib/components/file_size.dart | 15 ++ lib/components/mime_type.dart | 25 ++ lib/components/nextcloud_routes.dart | 13 + lib/main.dart | 49 +--- lib/models/details.dart | 19 ++ lib/models/files.dart | 53 ++++ lib/provider/nextcloud_provider.dart | 182 +++++++++++++ lib/screens/home_screen.dart | 252 ++++++++++++++++++ lib/screens/login_screen.dart | 178 +++++++------ lib/screens/welcome_screen.dart | 27 -- lib/service/navigation_service.dart | 2 +- pubspec.lock | 384 ++++++++++++++++++++++++++- pubspec.yaml | 23 +- 22 files changed, 1275 insertions(+), 271 deletions(-) create mode 100644 assets/images/nextcloud_logo.png create mode 100644 devtools_options.yaml delete mode 100644 lib/api/login_api.dart create mode 100644 lib/app/extension.dart create mode 100644 lib/app/login_flow.dart create mode 100644 lib/app/nextcloud_app.dart delete mode 100644 lib/components/default_values.dart create mode 100644 lib/components/file_size.dart create mode 100644 lib/components/mime_type.dart create mode 100644 lib/components/nextcloud_routes.dart create mode 100644 lib/models/details.dart create mode 100644 lib/models/files.dart create mode 100644 lib/provider/nextcloud_provider.dart create mode 100644 lib/screens/home_screen.dart delete mode 100644 lib/screens/welcome_screen.dart diff --git a/.gitignore b/.gitignore index 222a16b..1eb9807 100644 --- a/.gitignore +++ b/.gitignore @@ -5,23 +5,27 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ -.dart_tool/ -macos/ -test/ -web/ -linux/ -windows/ -.rmv/ +*.metadeta +*main_sub_test* +*main_test* # IntelliJ related *.iml *.ipr *.iws -.idea/ +.idea/ +*.gitignore +*ios +*android +*.vscode +*pubspec.lock +*test/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line @@ -29,11 +33,8 @@ windows/ #.vscode/ # Flutter/Dart/Pub related -# **/doc/api/ -# **/ios/Flutter/.last_build_id - -*/doc/api/ -ios/ +**/doc/api/ +**/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies @@ -48,7 +49,6 @@ app.*.symbols app.*.map.json # Android Studio will place build artifacts here -# android/app/debug -# android/app/profile -# android/app/release -android/ \ No newline at end of file +/android/app/debug +/android/app/profile +/android/app/release diff --git a/.metadata b/.metadata index 6eb54a1..b02a7e4 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" + revision: "17025dd88227cd9532c33fa78f5250d548d87e9a" channel: "stable" project_type: app @@ -13,26 +13,26 @@ project_type: app migration: platforms: - platform: root - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: android - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: ios - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: linux - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: macos - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: web - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: windows - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a # User provided section diff --git a/assets/images/nextcloud_logo.png b/assets/images/nextcloud_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e1c08451f998cba9d518d2b6b6718082bf4b5bc1 GIT binary patch literal 94420 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� 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%0DiH`ASXK$ljG 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�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 QK?1&% login(String uri, String username, String password) async { - try { - - final client = NextcloudClient( - Uri.parse(uri), - loginName: username, - password: password, - ); - - - final response = - await client.provisioningApi.users.getUser(userId: username); - - if (response.statusCode == 200) { - print(response.body); - return "successful|$response.body.ocs.data."; - } else { - return "failed|$response.body.ocs.data"; - } - } catch (e) { - print(""); - print("$e"); - print(""); - return "$e"; - } -} diff --git a/lib/app/extension.dart b/lib/app/extension.dart new file mode 100644 index 0000000..4055bae --- /dev/null +++ b/lib/app/extension.dart @@ -0,0 +1,19 @@ +import 'dart:io'; + +import 'package:http/io_client.dart'; +import 'package:nextcloud/nextcloud.dart'; + + +extension NextcloudClientExtension on NextcloudClient { + // + static final userAgent = 'NextCloud App' + '(${Platform.operatingSystem}) '; + // 'Dart/${Platform.version.split(' ').first}'; + + // + static IOClient newHttpClient() => IOClient( + HttpClient()..userAgent = userAgent, + ); + + +} diff --git a/lib/app/login_flow.dart b/lib/app/login_flow.dart new file mode 100644 index 0000000..9b5eaa3 --- /dev/null +++ b/lib/app/login_flow.dart @@ -0,0 +1,104 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter_web_auth_2/flutter_web_auth_2.dart'; +import 'package:http/http.dart' as http; +import 'package:logging/logging.dart'; +import 'package:nextcloud/core.dart'; +import 'package:nextcloud/nextcloud.dart'; +import 'package:nextcloudapp/app/extension.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class SaberLoginFlow { + SaberLoginFlow.start({ + required this.serverUrl, + }) { + // NcHttpOverrides.tempAcceptBadCertificateFrom(serverUrl); + unawaited(_run()); + } + + final Uri serverUrl; + + final log = Logger('SaberLoginFlow'); + Timer? _pollTimer; + + final completer = Completer(); + late final future = completer.future; + + LoginFlowV2? init; + + Future openLoginUrl() async { + final init = this.init; + if (init == null) return; + + if (Platform.isMacOS || Platform.isIOS || Platform.isAndroid) { + // Use FlutterWebAuth2 which returns to Saber when authenticated + log.info('Opening login link in-app: ${init.login}'); + await FlutterWebAuth2.authenticate( + url: init.login, + callbackUrlScheme: 'nc', + ); + } else { + // Use url_launcher to open the link in the default browser + log.info('Opening login link in browser: ${init.login}'); + final loginLink = Uri.parse(init.login); + await launchUrl(loginLink); + } + } + + Future _run() async { + _catchHttpError(() async { + final client = NextcloudClient(serverUrl, + httpClient: NextcloudClientExtension.newHttpClient()); + final flowClient = client.core.clientFlowLoginV2; + init = await flowClient.init().then((response) => response.body); + log.info('init: $init'); + + openLoginUrl(); + + _pollTimer?.cancel(); + _pollTimer = Timer.periodic( + const Duration(seconds: 1), + (_) => _catch404Error(() async { + // Throws 404 if not logged in yet + final poll = await flowClient.poll( + $body: ClientFlowLoginV2PollRequestApplicationJson( + (b) => b..token = init!.poll.token, + ), + ); + + _pollTimer?.cancel(); + if (!completer.isCompleted) completer.complete(poll.body); + }), + ); + }); + } + + Future _catchHttpError(Future Function() fn) async { + try { + return await fn(); + } on http.ClientException catch (error, stackTrace) { + log.severe('Error while polling the login flow.', error, stackTrace); + if (!completer.isCompleted) completer.completeError(error, stackTrace); + return null; + } + } + + Future _catch404Error(Future Function() fn) async { + try { + return await fn(); + } on DynamiteStatusCodeException catch (error) { + if (error.statusCode != 404) rethrow; + + log.fine('Login flow not found or completed yet, will repoll'); + return null; + } + } + + void dispose() { + _pollTimer?.cancel(); + if (!completer.isCompleted) { + completer.completeError(TimeoutException('Login flow was disposed')); + } + } +} diff --git a/lib/app/nextcloud_app.dart b/lib/app/nextcloud_app.dart new file mode 100644 index 0000000..e582c22 --- /dev/null +++ b/lib/app/nextcloud_app.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:nextcloudapp/components/nextcloud_routes.dart'; +import 'package:nextcloudapp/service/navigation_service.dart'; + +class NextcloudApp extends StatelessWidget { + NextcloudApp({ + super.key, + }); + + final NextcloudAppRoutes _nextcloudAppRoutes = NextcloudAppRoutes.instance; + final NavigationService _navigationService = NavigationService.instance; + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + title: 'Nextcloud App', + navigatorKey: _navigationService.navigatorKey, + theme: ThemeData( + primaryColor: Color.fromARGB(255, 152, 120, 57), + scaffoldBackgroundColor: Colors.white, + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + elevation: 0, + foregroundColor: Colors.white, + backgroundColor: Color.fromARGB(255, 152, 120, 57), + shape: const StadiumBorder(), + maximumSize: const Size(double.infinity, 56), + minimumSize: const Size(double.infinity, 56), + ), + ), + // inputDecorationTheme: const InputDecorationTheme( + // filled: true, + // fillColor: primaryLightColor, + // iconColor: primaryColor, + // prefixIconColor: primaryColor, + // contentPadding: EdgeInsets.symmetric( + // horizontal: defaultPadding, vertical: defaultPadding), + // border: OutlineInputBorder( + // borderRadius: BorderRadius.all(Radius.circular(30)), + // borderSide: BorderSide.none, + // ), + // ), + fontFamily: 'Poppins', + ), + routes: _nextcloudAppRoutes.routes, + initialRoute: "login", + ); + } +} diff --git a/lib/components/default_values.dart b/lib/components/default_values.dart deleted file mode 100644 index 98888c7..0000000 --- a/lib/components/default_values.dart +++ /dev/null @@ -1,54 +0,0 @@ -// import 'package:nextcloud/nextcloud.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter/material.dart'; -// import 'package:http/http.dart' as http; - - - -const primaryColor = Color.fromARGB(255, 26, 26, 74); -const primaryLightColor = Color.fromARGB(150, 238, 224, 173); -const double defaultPadding = 15.0; -const timeout = 3; -// var client = http.Client(); -// var client = NextcloudClient() - - -setSharedPref(String key, var value) async { - SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); - - switch (value.runtimeType.toString()) { - case 'String': - sharedPreferences.setString(key, value); - break; - - case 'double': - sharedPreferences.setDouble(key, value); - break; - - case 'int': - sharedPreferences.setInt(key, value); - break; - - case 'bool': - sharedPreferences.setBool(key, value); - break; - } -} - -getSharedPref(var key, var type) async { - SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); - - switch (type) { - case 'String': - return sharedPreferences.getString(key); - - case 'double': - return sharedPreferences.getDouble(key); - - case 'int': - return sharedPreferences.getInt(key); - - case 'bool': - return sharedPreferences.getBool(key); - } -} \ No newline at end of file diff --git a/lib/components/file_size.dart b/lib/components/file_size.dart new file mode 100644 index 0000000..79236d6 --- /dev/null +++ b/lib/components/file_size.dart @@ -0,0 +1,15 @@ +import 'dart:math'; + +class FileSize { + static FileSize instance = FileSize(); + + String getFileSizeString({required int bytes, int decimals = 0}) { + const suffixes = ["Bytes", "KB", "MB", "GB", "TB"]; + if (bytes == 0) return '0 ${suffixes[0]}'; + + var i = (log(bytes) / log(1024)).floor(); + return "${(bytes / pow(1024, i)).toStringAsFixed( + i == 0 ? 0 : decimals, + )} ${suffixes[i]}"; + } +} diff --git a/lib/components/mime_type.dart b/lib/components/mime_type.dart new file mode 100644 index 0000000..a0961e1 --- /dev/null +++ b/lib/components/mime_type.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +class MimetypeIcon { + static MimetypeIcon instance = MimetypeIcon(); + + IconData getIconForMimeType(String mimeType) { + if (mimeType.startsWith('image/')) { + return Icons.image; + } else if (mimeType.startsWith('video/')) { + return Icons.video_file; + } else if (mimeType.startsWith('audio/')) { + return Icons.audiotrack; + } else if (mimeType == 'application/pdf') { + return Icons.picture_as_pdf; + } else if (mimeType.startsWith('text/')) { + return Icons.text_snippet; + } else if (mimeType.contains("application/octet-stream")) { + return Icons.disc_full_rounded; + } else if (mimeType.contains("application/zip")) { + return Icons.folder_zip; + } else { + return Icons.folder; // Default icon + } + } +} diff --git a/lib/components/nextcloud_routes.dart b/lib/components/nextcloud_routes.dart new file mode 100644 index 0000000..eb1f9fa --- /dev/null +++ b/lib/components/nextcloud_routes.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:nextcloudapp/screens/login_screen.dart'; +import 'package:nextcloudapp/screens/home_screen.dart'; + +class NextcloudAppRoutes { + // + static NextcloudAppRoutes instance = NextcloudAppRoutes(); + + Map get routes => { + "login": (BuildContext _context) => LoginScreen(), + "home": (BuildContext _context) => HomeSceen(), + }; +} diff --git a/lib/main.dart b/lib/main.dart index a862a85..14982e4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,48 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:nextcloudapp/components/default_values.dart'; -import 'package:nextcloudapp/screens/login_screen.dart'; +import 'package:nextcloudapp/app/nextcloud_app.dart'; -void main() => runApp( - const MyApp(), - ); +void main() { + WidgetsFlutterBinding.ensureInitialized(); -class MyApp extends StatelessWidget { - const MyApp({super.key}); + runApp( + NextcloudApp(), + ); - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - title: 'Nextcloud', - theme: ThemeData( - primaryColor: primaryColor, - scaffoldBackgroundColor: Colors.white, - elevatedButtonTheme: ElevatedButtonThemeData( - style: ElevatedButton.styleFrom( - elevation: 0, - foregroundColor: Colors.white, - backgroundColor: primaryColor, - shape: const StadiumBorder(), - maximumSize: const Size(double.infinity, 56), - minimumSize: const Size(double.infinity, 56), - ), - ), - inputDecorationTheme: const InputDecorationTheme( - filled: true, - fillColor: primaryLightColor, - iconColor: primaryColor, - prefixIconColor: primaryColor, - contentPadding: EdgeInsets.symmetric( - horizontal: defaultPadding, vertical: defaultPadding), - border: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(30)), - borderSide: BorderSide.none, - ), - ), - fontFamily: 'Poppins', - ), - home: const LoginScreen(), - ); - } } diff --git a/lib/models/details.dart b/lib/models/details.dart new file mode 100644 index 0000000..5d5188c --- /dev/null +++ b/lib/models/details.dart @@ -0,0 +1,19 @@ +import 'package:nextcloud/nextcloud.dart'; + +class ServerDetails { + String name; + String description; + + ServerDetails({ + required this.name, + required this.description, + }); + + factory ServerDetails.fromTheme(Map _themeValues) { + // + DynamiteResponse icon = _themeValues['icon']; + DynamiteResponse theme = _themeValues['systemtheme']; + + return ServerDetails(name: '', description: ''); + } +} diff --git a/lib/models/files.dart b/lib/models/files.dart new file mode 100644 index 0000000..aadea10 --- /dev/null +++ b/lib/models/files.dart @@ -0,0 +1,53 @@ +import 'package:nextcloud/webdav.dart'; + +class Files { + String? path; + String? name; + String? resourceType; + String? contentType; + DateTime? creationDate; + DateTime? modifiedDate; + int? size; + + Files({ + required this.path, + required this.name, + required this.resourceType, + required this.contentType, + required this.creationDate, + required this.modifiedDate, + required this.size, + }); + + factory Files.fromWebDavResponse(WebDavResponse _response) { +// + var _name; + var _resourceType; + var _size; + + var _tempPath = _response.href!.split("/"); + var _length = _tempPath.length; + var _collection = _response.propstats[0].prop.davResourcetype!.collection; + if (_collection == null) { + _resourceType = 'file'; + _name = _tempPath[_length - 1]; + _size = _response.propstats[0].prop.davGetcontentlength; + } else { + _resourceType = 'folder'; + _name = _tempPath[_length - 2].contains("dav") + ? ".." + : _tempPath[_length - 2]; + _size = _response.propstats[0].prop.davQuotaUsedBytes; + } + + return Files( + path: _response.href ?? '', + name: Uri.decodeFull(_name), + contentType: _response.propstats[0].prop.davGetcontenttype ?? '', + creationDate: DateTime.now(), + modifiedDate: _response.propstats[0].prop.davGetlastmodified, + size: _size, + resourceType: _resourceType, + ); + } +} diff --git a/lib/provider/nextcloud_provider.dart b/lib/provider/nextcloud_provider.dart new file mode 100644 index 0000000..95a3559 --- /dev/null +++ b/lib/provider/nextcloud_provider.dart @@ -0,0 +1,182 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:nextcloud/core.dart'; +import 'package:nextcloud/nextcloud.dart'; +import 'package:nextcloud/provisioning_api.dart'; +import 'package:nextcloud/theming.dart'; +import 'package:nextcloud/webdav.dart'; +import 'package:nextcloudapp/app/extension.dart'; +import 'package:nextcloudapp/models/details.dart'; +import 'package:nextcloudapp/models/files.dart'; + +import 'package:nextcloudapp/service/navigation_service.dart'; +import 'package:nextcloudapp/service/snackbar_service.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +enum AuthStatus { + notAuthenticated, + authenticated, + authenticating, + userNotFound, + error, +} + +class NextcloudProvider extends ChangeNotifier { + // + // + + static NextcloudProvider instance = NextcloudProvider(); + final NavigationService _navigationService = NavigationService.instance; + + late NextcloudClient client; + final SharedPreferencesAsync _sharedPreferences = SharedPreferencesAsync(); + // SharedPreferences? _sharedPreferences; + + AuthStatus? status; + UserDetails? userDetails; + + NextcloudProvider() { + // _init(); + _checkLogin(); + } + + // void _init() async { + // _sharedPreferences = SharedPreferencesAsync(); + // } + + void _checkLogin() async { + await Future.delayed(Duration(milliseconds: 300)); + try { + String? _appPassword = await _sharedPreferences.getString('apppassword'); + print(_appPassword); + String? _uri = await _sharedPreferences.getString('uri'); + if (_appPassword != null && _uri != null) { + client = NextcloudClient( + Uri.parse(_uri), + appPassword: _appPassword, + httpClient: NextcloudClientExtension.newHttpClient(), + ); + + var _user = await client.provisioningApi.users.getCurrentUser(); + userDetails = _user.body.ocs.data; + + status = AuthStatus.authenticated; + _navigationService.navigateToReplacement("home"); + } else { + status = AuthStatus.notAuthenticated; + } + } on Exception catch (e) { + status = AuthStatus.notAuthenticated; + SnackBarService.instance.showSnackBarError("$e"); + } + } + + Future envData() async { + Map _themeValues = {}; + + _themeValues['icon'] = await client.theming.icon.getFavicon(); + _themeValues['systemtheme'] = await client.theming.theming.getManifest(); + + return ServerDetails.fromTheme(_themeValues); + } + + Future login(String _uri, String _username, String _password, + bool _savePassword) async { + notifyListeners(); + status = AuthStatus.error; + try { + status = AuthStatus.authenticating; + client = NextcloudClient( + Uri.parse(_uri), + loginName: _username, + password: _password, + httpClient: NextcloudClientExtension.newHttpClient(), + ); + var _user = await client.provisioningApi.users.getCurrentUser(); + userDetails = _user.body.ocs.data; + client.core.appPassword.getAppPassword().then((_response) async { + await _sharedPreferences.setString( + 'apppassword', _response.body.ocs.data.apppassword); + await _sharedPreferences.setString('uri', _uri); + await _sharedPreferences.setString('username', _username); + if (_savePassword) { + await _sharedPreferences.setString('password', _password); + } + }); + + status = AuthStatus.authenticated; + SnackBarService.instance.showSnackBarSuccess('successfully logged in'); + _navigationService.navigateToReplacement("home"); + } on ClientException catch (e) { + SnackBarService.instance.showSnackBarError("$e"); + status = AuthStatus.error; + } on Exception catch (e) { + status = AuthStatus.error; + SnackBarService.instance.showSnackBarError("$e"); + } + notifyListeners(); + } + + void logout() async { + try { + var _resp = await client.core.appPassword.deleteAppPassword(); + if (_resp.statusCode == 200) { + _sharedPreferences.remove('apppassword'); + SnackBarService.instance.showSnackBarSuccess("succssfully loggedout"); + _navigationService.navigateToReplacement("login"); + } else { + SnackBarService.instance + .showSnackBarError(_resp.body.ocs.meta.message!); + } + } on Exception catch (e) { + SnackBarService.instance.showSnackBarError("$e"); + } + } + + Future> listDirectory(String _cd) async { + List _fileList = []; + + try { + WebDavClient _client = client.webdav; + var _returnVal = await _client.propfind( + PathUri.parse(Uri.decodeFull(_cd)), + prop: WebDavPropWithoutValues(), + depth: WebDavDepth.one, + ); + + _fileList = _returnVal.responses.map((_value) { + return Files.fromWebDavResponse(_value); + }).toList(); + + _fileList[0].name = ".."; + _fileList[0].size = 0; + _fileList[0].resourceType = 'folder'; + List filteredList = List.from(_fileList)..removeAt(0); + filteredList.sort((a, b) => b.resourceType!.compareTo(a.resourceType!)); + filteredList.insert(0, _fileList[0]); + return filteredList; + } on Exception catch (e) { + print(e.toString()); + return Future.delayed(Duration.zero); + } + } + + Future getIt() async { + Directory? storageDirectory = await getApplicationDocumentsDirectory(); + String _sdPath = storageDirectory.path; + var d = Directory(_sdPath); + if (!d.existsSync()) { + d.createSync(recursive: true); + File _fileTemp = File("$_sdPath/.nomedia"); + _fileTemp.writeAsString(''); + } + + // File temp = File('$_sdPath/temp.png'); + + // await _client.getFile( + // PathUri.parse("/files/${userDetails!.id}/Nextcloud.png"), temp); + } +} diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart new file mode 100644 index 0000000..104d84c --- /dev/null +++ b/lib/screens/home_screen.dart @@ -0,0 +1,252 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:intl/intl.dart'; +import 'package:nextcloud/webdav.dart'; +import 'package:nextcloudapp/components/file_size.dart'; +import 'package:nextcloudapp/models/files.dart'; +import 'package:nextcloudapp/provider/nextcloud_provider.dart'; +import 'package:nextcloudapp/service/snackbar_service.dart'; +import 'package:nextcloudapp/components/mime_type.dart'; +import 'package:file_icon/file_icon.dart'; + +class HomeSceen extends StatefulWidget { + const HomeSceen({super.key}); + + @override + State createState() => _HomeSceenState(); +} + +class _HomeSceenState extends State { +// + var _deviceHeight; + var _deviceWidth; + var _percentage; + var _usedMemory; + var _totalMemory; + var _cwd; + + List _temp = []; + List? _data = []; + + final MimetypeIcon _mimetypeIcon = MimetypeIcon.instance; + final FileSize _fileSize = FileSize.instance; + final NextcloudProvider _provider = NextcloudProvider.instance; + + final ScrollController _scrollController = ScrollController(); + + _HomeSceenState() { + _cwd = ""; + } + + @override + Widget build(BuildContext context) { + _deviceHeight = MediaQuery.of(context).size.height; + _deviceWidth = MediaQuery.of(context).size.width; + SnackBarService.instance.buildContext = context; + return Scaffold( + appBar: AppBar( + title: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Container( + height: _deviceHeight * 0.10, + width: _deviceWidth * 0.20, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + image: DecorationImage( + image: AssetImage('assets/images/nextcloud_logo.png'), + ), + ), + ), + Text("NextCloud"), + ], + ), + ), + drawer: _appDrawerUI(), + body: _appBodyUI(), + floatingActionButton: _floatingButton()); + } + + Widget _floatingButton() { + return SpeedDial( + closeManually: true, + animatedIcon: AnimatedIcons.menu_arrow, + children: [ + SpeedDialChild( + label: "File Upload", + child: Icon(Icons.upload), + ), + SpeedDialChild( + label: "Folder Upload", + child: Icon(Icons.upload), + ), + ], + ); + } + + Widget _appDrawerUI() { + _totalMemory = _provider.userDetails!.quota.total; + _usedMemory = _provider.userDetails!.quota.used; + _percentage = (_usedMemory / _totalMemory); + return NavigationDrawer( + backgroundColor: Color.fromARGB(255, 72, 160, 232), + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + SizedBox( + height: _deviceHeight * 0.05, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Text(_provider.userDetails!.displayName), + IconButton( + onPressed: () { + _provider.logout(); + }, + icon: Icon(Icons.logout_sharp), + ), + ], + ), + ), + SizedBox( + height: _deviceHeight * 0.20, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Text( + 'Memory Usage', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + SizedBox(height: 10), + LinearProgressIndicator( + value: _percentage, + backgroundColor: Colors.grey[300], + valueColor: AlwaysStoppedAnimation( + _percentage > 0.80 ? Colors.red : Colors.green, + ), + ), + SizedBox(height: 10), + Text( + '${(_percentage * 100).toStringAsFixed(2)}% used', + style: TextStyle(fontSize: 14), + ), + Text( + '${_fileSize.getFileSizeString( + bytes: _usedMemory, + decimals: 1, + )} of ${_fileSize.getFileSizeString( + bytes: _totalMemory, + decimals: 1, + )}', + style: TextStyle(fontSize: 14), + ), + ], + ), + ) + ], + ), + ], + ); + } + + Widget _appBodyUI() { + return SizedBox( + height: _deviceHeight * 0.80, + child: FutureBuilder( + future: _provider.listDirectory(_cwd), + builder: (context, _snapshot) { + _data = _snapshot.data; + if (_data != null) { + // WidgetsBinding.instance.addPostFrameCallback( + // (_) { + // if (_scrollController.hasClients) { + // _scrollController + // .jumpTo(_scrollController.position.minScrollExtent); + // } + // }, + // ); + + return Scrollbar( + controller: _scrollController, + child: ListView.builder( + controller: _scrollController, + itemCount: _data!.length, + itemBuilder: (BuildContext _context, int _index) { + return ListTile( + onLongPress: () {}, + onTap: () { + setState(() { + if (_data![_index].resourceType! == "folder") { + if (_index == 0) { + _temp.removeAt(_temp.length - 2); + _cwd = _temp + .join("/") + .replaceAll(webdavBase.toString(), ''); + } else { + _cwd = _data![_index] + .path! + .replaceAll(webdavBase.toString(), ''); + _temp = _data![_index].path!.split("/"); + } + } + }); + }, + leading: _data![_index].resourceType! == 'folder' + ? Icon(_mimetypeIcon + .getIconForMimeType(_data![_index].contentType!)) + : FileIcon( + _data![_index].name!, + size: 32.0, + ), + title: Text( + _data![_index].name!, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 15), + ), + subtitle: Text( + _index == 0 + ? '' + : DateFormat('dd MMM, yyyy hh:mm a') + .format(_data![_index].modifiedDate!), + style: TextStyle( + fontSize: 12, + ), + ), + trailing: Text( + _index != 0 + ? _fileSize.getFileSizeString( + bytes: _data![_index].size!, + decimals: 2, + ) + : '', + ), + ); + }, + ), + ); + } else if (_snapshot.hasError) { + return Align( + child: Text("No Data"), + ); + } else if (_snapshot.connectionState == ConnectionState.waiting) { + return Align( + child: CircularProgressIndicator(), + ); + } else { + return Align( + child: Text("Undecided"), + ); + ; + } + }, + ), + ); + } +} diff --git a/lib/screens/login_screen.dart b/lib/screens/login_screen.dart index 43b73c9..86ce8a7 100644 --- a/lib/screens/login_screen.dart +++ b/lib/screens/login_screen.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:nextcloudapp/api/login_api.dart'; -import 'package:nextcloudapp/components/default_values.dart'; -import 'package:nextcloudapp/screens/welcome_screen.dart'; +import 'package:nextcloudapp/provider/nextcloud_provider.dart'; import 'package:nextcloudapp/service/snackbar_service.dart'; +import 'package:provider/provider.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -14,44 +13,55 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State { var _deviceHeight; var _deviceWidth; - var urlController; - var usernameController; - var passwordController; - - final GlobalKey _formKey = GlobalKey(); - - var checked = false; + var _url; + var _username; + var _password; + var enableInput = true; + var savePassword = false; var obscureText = true; + NextcloudProvider _provider = NextcloudProvider.instance; + final GlobalKey _formKey = GlobalKey(); + @override Widget build(BuildContext context) { - SnackBarService.instance.buildContext = context; _deviceHeight = MediaQuery.of(context).size.height; _deviceWidth = MediaQuery.of(context).size.width; return Scaffold( body: Align( - child: Container( - height: _deviceHeight * 0.60, - padding: EdgeInsets.symmetric(horizontal: _deviceWidth * 0.05), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _inputField(), - _passwordSaveField(), - _signInField(), - ], - ), + child: ChangeNotifierProvider.value( + value: _provider, + child: _loginPage(), ), ), ); } - Widget _inputField() { + Widget _loginPage() { + return Builder(builder: (BuildContext _context) { + SnackBarService.instance.buildContext = _context; + _provider = Provider.of(_context); + return Container( + height: _deviceHeight * 0.80, + padding: EdgeInsets.symmetric(horizontal: _deviceWidth * 0.05), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _inputForm(), + _passwordSaveField(), + _signInButton(_context), + ], + ), + ); + }); + } + + Widget _inputForm() { return SizedBox( - height: _deviceHeight * 0.25, + height: _deviceHeight * 0.27, child: Form( key: _formKey, onChanged: () { @@ -63,64 +73,84 @@ class _LoginScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ TextFormField( + initialValue: "https://storage.theonasanyas.com", + enabled: enableInput, keyboardType: TextInputType.url, textInputAction: TextInputAction.next, - cursorColor: Colors.white, + cursorColor: Colors.black, style: TextStyle( color: Colors.black, ), onSaved: (_input) { setState(() { - urlController = _input!; + _url = _input!; }); }, validator: (_input) { - return null; + return _input!.isNotEmpty ? null : "nnnns"; }, - decoration: const InputDecoration( + decoration: InputDecoration( hintText: "hosting URL", focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.white) - ), + borderSide: BorderSide(color: Colors.white)), prefixIcon: Padding( - padding: EdgeInsets.all(defaultPadding), + padding: EdgeInsets.all(15.0), child: Icon(Icons.computer_outlined), ), ), ), TextFormField( + initialValue: "fluttertest", + enabled: enableInput, keyboardType: TextInputType.emailAddress, textInputAction: TextInputAction.next, + cursorColor: Colors.black, style: TextStyle( color: Colors.black, ), onSaved: (_input) { + if (_input == null) {} setState(() { - usernameController = _input!; + _username = _input!; }); }, - decoration: const InputDecoration( + validator: (_input) { + return _input!.isNotEmpty ? null : "nnnns"; + }, + decoration: InputDecoration( hintText: "username", + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.white)), prefixIcon: Padding( - padding: EdgeInsets.all(defaultPadding), + padding: EdgeInsets.all(15.0), child: Icon(Icons.person), ), ), ), TextFormField( + initialValue: "9tWx8XAv545+ijnBxOrh", + enabled: enableInput, keyboardType: TextInputType.visiblePassword, textInputAction: TextInputAction.done, + cursorColor: Colors.black, + style: TextStyle( + color: Colors.black, + ), obscureText: obscureText, onSaved: (_input) { setState(() { - passwordController = _input!; + _password = _input!; }); }, - cursorColor: primaryColor, + validator: (_input) { + return _input!.isNotEmpty ? null : "nnnns"; + }, decoration: InputDecoration( - hintText: "Password", + hintText: "password", + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.white)), prefixIcon: const Padding( - padding: EdgeInsets.all(defaultPadding), + padding: EdgeInsets.all(15.0), child: Icon(Icons.lock), ), suffixIcon: IconButton( @@ -146,51 +176,45 @@ class _LoginScreenState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Checkbox( - value: checked, + value: savePassword, onChanged: (value) { setState(() { - checked = value!; + savePassword = value!; }); }), - const Text('Save Password'), + const Text('save password'), ], ); } - Widget _signInField() { - return ElevatedButton( - onPressed: () { - login(urlController.value.text, usernameController.value.text, - passwordController.value.text) - .then(( - status, - ) { - if (status.startsWith('successful')) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return const WelcomeScreen(); - }, + Widget _signInButton(BuildContext _context) { + return _provider.status == AuthStatus.authenticating + ? Align( + alignment: Alignment.center, + child: CircularProgressIndicator(), + ) + : SizedBox( + height: _deviceHeight * 0.06, + width: _deviceWidth * 0.30, + child: MaterialButton( + onPressed: () async { + enableInput = !enableInput; + if (_formKey.currentState!.validate()) { + //Login User + await _provider.login( + _url, _username, _password, savePassword); + } + enableInput = !enableInput; + }, + color: Colors.grey, + child: Text( + 'login', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w700, + ), ), - ); - - SnackBarService.instance.showSnackBarSuccess(status); - } else { - SnackBarService.instance.showSnackBarError(status); - } - }); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "sign in".toUpperCase(), - ), - const SizedBox(width: 10), - const Icon(Icons.login) - ], - ), - ); + ), + ); } } diff --git a/lib/screens/welcome_screen.dart b/lib/screens/welcome_screen.dart deleted file mode 100644 index c072817..0000000 --- a/lib/screens/welcome_screen.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -class WelcomeScreen extends StatefulWidget { - const WelcomeScreen({super.key}); - - @override - State createState() => _WelcomeScreenState(); -} - -class _WelcomeScreenState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - return const Scaffold( - body: Column( - children: [ - - - ], - ), - ); - } -} diff --git a/lib/service/navigation_service.dart b/lib/service/navigation_service.dart index b0bab56..c468639 100644 --- a/lib/service/navigation_service.dart +++ b/lib/service/navigation_service.dart @@ -10,7 +10,7 @@ class NavigationService { navigatorKey = GlobalKey(); } - Future? navigateToReplacement(String _routeName) { + Future navigateToReplacement(String _routeName) { return navigatorKey!.currentState!.pushReplacementNamed(_routeName); } diff --git a/pubspec.lock b/pubspec.lock index 8ffa3ec..e057562 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -34,7 +34,7 @@ packages: source: hosted version: "2.1.1" built_collection: - dependency: transitive + dependency: "direct main" description: name: built_collection sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" @@ -81,6 +81,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" crypto: dependency: transitive description: @@ -105,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + desktop_webview_window: + dependency: transitive + description: + name: desktop_webview_window + sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0" + url: "https://pub.dev" + source: hosted + version: "0.2.3" dynamite_runtime: dependency: transitive description: @@ -113,6 +129,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0+1" + easy_image_viewer: + dependency: "direct main" + description: + name: easy_image_viewer + sha256: fb6cb123c3605552cc91150dcdb50ca977001dcddfb71d20caa0c5edc9a80947 + url: "https://pub.dev" + source: hosted + version: "1.5.1" fake_async: dependency: transitive description: @@ -137,6 +161,54 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + file_icon: + dependency: "direct main" + description: + name: file_icon + sha256: c46b6c24d9595d18995758b90722865baeda407f56308eadd757e1ab913f50a1 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "77f8e81d22d2a07d0dee2c62e1dda71dc1da73bf43bb2d45af09727406167964" + url: "https://pub.dev" + source: hosted + version: "10.1.9" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" fixnum: dependency: transitive description: @@ -150,6 +222,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_context_menu: + dependency: "direct main" + description: + name: flutter_context_menu + sha256: "5e9c62a5937aba135e3787711b04c73b78729a9751c6c71c2bece4ed9a480d76" + url: "https://pub.dev" + source: hosted + version: "0.2.4" flutter_lints: dependency: "direct dev" description: @@ -158,6 +238,30 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e + url: "https://pub.dev" + source: hosted + version: "2.0.28" + flutter_speed_dial: + dependency: "direct main" + description: + name: flutter_speed_dial + sha256: "698a037274a66dbae8697c265440e6acb6ab6cae9ac5f95c749e7944d8f28d41" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + flutter_spinkit: + dependency: "direct main" + description: + name: flutter_spinkit + sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472 + url: "https://pub.dev" + source: hosted + version: "5.2.1" flutter_svg: dependency: "direct main" description: @@ -171,6 +275,22 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_auth_2: + dependency: "direct main" + description: + name: flutter_web_auth_2 + sha256: "3c14babeaa066c371f3a743f204dd0d348b7d42ffa6fae7a9847a521aff33696" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + flutter_web_auth_2_platform_interface: + dependency: transitive + description: + name: flutter_web_auth_2_platform_interface + sha256: c63a472c8070998e4e422f6b34a17070e60782ac442107c70000dd1bed645f4d + url: "https://pub.dev" + source: hosted + version: "4.1.0" flutter_web_plugins: dependency: transitive description: flutter @@ -192,6 +312,70 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb" + url: "https://pub.dev" + source: hosted + version: "0.8.12+23" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" + source: hosted + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" intl: dependency: "direct main" description: @@ -241,7 +425,7 @@ packages: source: hosted version: "5.1.1" logging: - dependency: transitive + dependency: "direct main" description: name: logging sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 @@ -272,6 +456,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.15.0" + mime: + dependency: "direct main" + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" nextcloud: dependency: "direct main" description: @@ -296,6 +496,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 + url: "https://pub.dev" + source: hosted + version: "2.2.17" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" + source: hosted + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -320,6 +544,54 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" + url: "https://pub.dev" + source: hosted + version: "11.4.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc + url: "https://pub.dev" + source: hosted + version: "12.1.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" petitparser: dependency: transitive description: @@ -352,6 +624,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.9.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" quiver: dependency: transitive description: @@ -364,10 +644,10 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.3" shared_preferences_android: dependency: transitive description: @@ -469,6 +749,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.3" + timeago: + dependency: "direct main" + description: + name: timeago + sha256: b05159406a97e1cbb2b9ee4faa9fb096fe0e2dfcd8b08fcd2a00553450d3422e + url: "https://pub.dev" + source: hosted + version: "3.7.1" timezone: dependency: transitive description: @@ -485,6 +773,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + units_converter: + dependency: "direct main" + description: + name: units_converter + sha256: dfb40a9bd0df48701466ae17fd9a763eed3abe9b98b97be1d04a2fecb99673a6 + url: "https://pub.dev" + source: hosted + version: "3.0.3" universal_io: dependency: transitive description: @@ -501,6 +797,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" + url: "https://pub.dev" + source: hosted + version: "6.3.16" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" vector_graphics: dependency: transitive description: @@ -557,6 +917,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + win32: + dependency: transitive + description: + name: win32 + sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e + url: "https://pub.dev" + source: hosted + version: "5.10.1" + window_to_front: + dependency: transitive + description: + name: window_to_front + sha256: "7aef379752b7190c10479e12b5fd7c0b9d92adc96817d9e96c59937929512aee" + url: "https://pub.dev" + source: hosted + version: "0.0.3" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e4754ec..68e5c7c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,14 +12,29 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 flutter_svg: ^2.0.17 http: ^1.3.0 - intl: ^0.20.2 - shared_preferences: ^2.5.2 + shared_preferences: ^2.5.3 nextcloud: ^8.1.0 + provider: ^6.1.2 + image_picker: ^1.1.2 + timeago: ^3.7.0 + easy_image_viewer: ^1.5.1 + permission_handler: ^11.4.0 + path_provider: ^2.1.5 + mime: ^2.0.0 + built_collection: ^5.1.1 + flutter_web_auth_2: ^4.1.0 + logging: ^1.3.0 + url_launcher: ^6.3.1 + flutter_spinkit: ^5.2.1 + units_converter: ^3.0.3 + file_icon: ^1.0.0 + intl: ^0.20.2 + flutter_speed_dial: ^7.0.0 + file_picker: ^10.1.9 + flutter_context_menu: ^0.2.4 dev_dependencies: flutter_test: