From f530a52e9d267aae306b46dd6849d5c8deeb2137 Mon Sep 17 00:00:00 2001 From: Julian Mutter Date: Wed, 18 Dec 2024 00:36:33 +0100 Subject: [PATCH] Work on implementing sheetable client --- lib/api.dart | 206 ++++++++++ lib/main.dart | 71 ++-- lib/sheet.dart | 87 ++-- lib/sheetview.dart | 53 ++- macos/Flutter/GeneratedPluginRegistrant.swift | 6 +- pubspec.lock | 370 +++++++++++++----- pubspec.yaml | 5 +- web/index.html | 31 +- 8 files changed, 620 insertions(+), 209 deletions(-) create mode 100644 lib/api.dart diff --git a/lib/api.dart b/lib/api.dart new file mode 100644 index 0000000..2a9d6f4 --- /dev/null +++ b/lib/api.dart @@ -0,0 +1,206 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; +import 'package:path_provider/path_provider.dart'; // For cache storage +import 'package:file/memory.dart'; + +import 'sheet.dart'; + +class ApiClient { + final String baseUrl = + 'http://localhost:8080/api'; // Replace with your API base URL + String? _token; // Holds the JWT token after login + + /// Checks if the user is authenticated + bool get isAuthenticated => _token != null; + + /// Login and store the JWT token + Future login(String username, String password) async { + print("Logging in..."); + try { + final url = '$baseUrl/login'; + final response = await http.post( + Uri.parse(url), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({ + 'email': username, + 'password': password, + }), + ); + + if (response.statusCode == 200) { + _token = jsonDecode(response.body); + print('Login successful, token: $_token'); + return true; + } else { + print('Login failed: ${response.statusCode}, ${response.body}'); + } + } catch (e) { + print('Error during login: $e'); + } + return false; + } + + /// Logout and clear the token + void logout() { + _token = null; + print('Logged out successfully.'); + } + + /// Make a GET request + Future get(String endpoint, {bool isBinary = false}) async { + try { + final url = '$baseUrl$endpoint'; + final headers = { + 'Authorization': 'Bearer $_token', + if (!isBinary) 'Content-Type': 'application/json', + }; + + final response = await http.get(Uri.parse(url), headers: headers); + + if (response.statusCode == 200) { + return response; + } else { + print('GET request failed: ${response.statusCode} ${response.body}'); + } + } catch (e) { + print('Error during GET request: $e'); + } + return null; + } + + /// Make a POST request + Future post( + String endpoint, Map body) async { + try { + final url = '$baseUrl$endpoint'; + final headers = { + 'Authorization': 'Bearer $_token', + 'Content-Type': 'application/json', + }; + + final response = await http.post( + Uri.parse(url), + headers: headers, + body: jsonEncode(body), + ); + + if (response.statusCode == 200 || response.statusCode == 201) { + return response; + } else { + print('POST request failed: ${response.statusCode} ${response.body}'); + } + } catch (e) { + print('Error during POST request: $e'); + } + return null; + } + + /// Make a POST request with form data + Future postFormData(String endpoint, String body) async { + try { + final url = '$baseUrl$endpoint'; + final headers = { + 'Authorization': 'Bearer $_token', + 'Content-Type': 'application/x-www-form-urlencoded', + }; + + final response = await http.post( + Uri.parse(url), + headers: headers, + body: body, + ); + + if (response.statusCode == 200 || response.statusCode == 201) { + return response; + } else { + print( + 'POST Form Data request failed: ${response.statusCode} ${response.body}'); + } + } catch (e) { + print('Error during POST Form Data request: $e'); + } + return null; + } + + Future> fetchSheets({String sortBy = "last_opened desc"}) async { + try { + final bodyFormData = { + "page": 1, + "limit": "1000", + "sort_by": sortBy, + }; + + print("doing post..."); + final response = await postFormData("/sheets", jsonEncode(bodyFormData)); + print("got response..."); + + if (response == null) { + print("Empty reponse"); + return List.empty(); + } + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + print("Data: $data"); + return (data['rows'] as List) + .map((sheet) => Sheet.fromJson(sheet as Map)) + .toList(); + } else { + print('Failed to fetch sheets with status: ${response.statusCode}'); + print('Response: ${response.body}'); + } + } catch (e) { + print('Error during fetching sheets: $e'); + } + + return List.empty(); + } + + Future getPdfFileCached(String sheetUuid) async { + try { + // Get the cache directory + + print("Creating cache dir..."); + // final cacheDir = kIsWeb + // ? await MemoryFileSystem().systemTempDirectory.createTemp('cache') + // : await getTemporaryDirectory(); + final cacheDir = await getTemporaryDirectory(); + final cachedPdfPath = '${cacheDir.path}/$sheetUuid.pdf'; + + print("cache dir created"); + + // Check if the file already exists in the cache + final cachedFile = File(cachedPdfPath); + + print("file created: $cachedFile"); + if (await cachedFile.exists()) { + print("PDF found in cache: $cachedPdfPath"); + return cachedFile; + } + + // Make the authenticated API call + + print("getting response"); + final response = await this.get('/sheet/pdf/$sheetUuid', isBinary: true); + + print("got response"); + if (response != null && response.statusCode == 200) { + // Save the fetched file to the cache + // + print("writing file...: $cachedFile"); + await cachedFile.writeAsBytes(response.bodyBytes); + print("PDF downloaded and cached at: $cachedPdfPath"); + return cachedFile; + } else { + print("Failed to fetch PDF from API. Status: ${response?.statusCode}"); + } + } catch (e) { + print("Error fetching PDF: $e"); + } + + return null; + } +} diff --git a/lib/main.dart b/lib/main.dart index 60d94d8..3228db6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:permission_handler/permission_handler.dart'; import 'package:saf/saf.dart'; import 'package:sheetless/sheetview.dart'; +import 'package:path_provider/path_provider.dart'; +import 'api.dart'; import 'sheet.dart'; void main() { @@ -33,38 +34,53 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { + ApiClient apiClient = ApiClient(); + Future apiLoggedIn = Future.value(false); + @override void initState() { super.initState(); + apiLoggedIn = apiClient.login("admin@admin.com", "sheetable"); } - Future getSafPickedSheetsDirectory() async { - await Permission.storage.request(); - await Permission.manageExternalStorage.request(); - var pickedDirectories = await Saf.getPersistedPermissionDirectories(); - if (pickedDirectories == null || pickedDirectories.isEmpty) { - return null; - } - return pickedDirectories.last; - } + // Future getSafPickedSheetsDirectory() async { + // await Permission.storage.request(); + // await Permission.manageExternalStorage.request(); + // var pickedDirectories = await Saf.getPersistedPermissionDirectories(); + // if (pickedDirectories == null || pickedDirectories.isEmpty) { + // return null; + // } + // return pickedDirectories.last; + // } Future> acquireSheets() async { - String? sheetsDirectory = await getSafPickedSheetsDirectory(); - if (sheetsDirectory == null || sheetsDirectory.isEmpty) { - await Saf.getDynamicDirectoryPermission(grantWritePermission: false); - sheetsDirectory = await getSafPickedSheetsDirectory(); - if (sheetsDirectory == null || sheetsDirectory.isEmpty) { - throw Exception("No Directory selected"); - } - } + // await Permission.storage.request(); + // await Permission.manageExternalStorage.request(); + // - var sheetsDirectoryFiles = await Saf.getFilesPathFor(sheetsDirectory); - if (sheetsDirectoryFiles == null) { - await Saf.releasePersistedPermissions(); - throw Exception( - "Permissions for directory no longer valid or Directory deleted. Please restart app."); - } - return loadSheetsSorted(sheetsDirectoryFiles); + await apiLoggedIn; // TODO: check if really logged in (returns bool) + return await apiClient.fetchSheets(); + // return api.main(); + + // final directory = await getApplicationDocumentsDirectory(); + // print("Directory is: $directory"); + // String? sheetsDirectory = "/home/julian/Klavier"; + // if (sheetsDirectory == null || sheetsDirectory.isEmpty) { + // await Saf.getDynamicDirectoryPermission(grantWritePermission: false); + // sheetsDirectory = "/home/julian/Klavier"; + // if (sheetsDirectory == null || sheetsDirectory.isEmpty) { + // throw Exception("No Directory selected"); + // } + // } + // return List.empty(); + + // var sheetsDirectoryFiles = await Saf.getFilesPathFor(sheetsDirectory); + // if (sheetsDirectoryFiles == null) { + // await Saf.releasePersistedPermissions(); + // throw Exception( + // "Permissions for directory no longer valid or Directory deleted. Please restart app."); + // } + // return loadSheetsSorted(sheetsDirectoryFiles); } @override @@ -82,7 +98,10 @@ class _MyHomePageState extends State { callback: (sheet) => Navigator.push( context, MaterialPageRoute( - builder: (context) => SheetViewerPage(sheet: sheet), + builder: (context) => SheetViewerPage( + sheet: sheet, + apiClient: apiClient, + ), ), ), ); diff --git a/lib/sheet.dart b/lib/sheet.dart index 19ca237..3815bc4 100644 --- a/lib/sheet.dart +++ b/lib/sheet.dart @@ -4,50 +4,53 @@ import 'package:flutter/material.dart'; import 'package:path/path.dart' as p; class Sheet { - final String author; + final String uuid; final String name; - final String path; + final String composerUuid; + final DateTime releaseDate; + final String file; + final String fileHash; + final bool wasUploaded; + final int uploaderId; + final DateTime createdAt; + final DateTime updatedAt; + final DateTime lastOpened; + final List tags; + final String informationText; - Sheet(this.author, this.name, this.path); -} + Sheet({ + required this.uuid, + required this.name, + required this.composerUuid, + required this.releaseDate, + required this.file, + required this.fileHash, + required this.wasUploaded, + required this.uploaderId, + required this.createdAt, + required this.updatedAt, + required this.lastOpened, + required this.tags, + required this.informationText, + }); -Future> loadSheetsSorted(List sheetsDirectoryFiles) async { - var sheets = await _loadSheets(sheetsDirectoryFiles); - sheets.sort((left, right) => left.name.compareTo(right.name)); - return sheets; -} - -Future> _loadSheets(List sheetsDirectoryFiles) async { - final List sheets = List.empty(growable: true); - var authorDirectories = sheetsDirectoryFiles - .map((e) => Directory(e)) - .where((element) => element.existsSync()); - - for (Directory authorDirectory in authorDirectories) { - var authorName = p.basename(authorDirectory.path); - // Ignore hidden directories - if (authorName.startsWith(".")) { - continue; - } - - await for (final FileSystemEntity sheetFile in authorDirectory.list()) { - if (sheetFile is File) { - var sheetName = p.basenameWithoutExtension(sheetFile.path); - // Ignore hidden files - if (sheetName.startsWith(".")) { - continue; - } - sheetName = sheetName.capitalize(); - sheets.add(Sheet(authorName, sheetName, sheetFile.path)); - } - } - } - return sheets; -} - -extension StringExtension on String { - String capitalize() { - return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; + // Factory constructor for creating a Sheet from JSON + factory Sheet.fromJson(Map json) { + return Sheet( + uuid: json['uuid'], + name: json['sheet_name'], + composerUuid: json['composer_uuid'], + releaseDate: DateTime.parse(json['release_date']), + file: json['file'], + fileHash: json['file_hash'], + wasUploaded: json['was_uploaded'], + uploaderId: json['uploader_id'], + createdAt: DateTime.parse(json['created_at']), + updatedAt: DateTime.parse(json['updated_at']), + lastOpened: DateTime.parse(json['last_opened']), + tags: List.from(json['tags']), + informationText: json['information_text'], + ); } } @@ -65,7 +68,7 @@ class SheetsWidget extends StatelessWidget { var sheet = sheets[index]; return ListTile( title: Text(sheet.name), - subtitle: Text(sheet.author), + subtitle: Text(sheet.uuid), onTap: () => callback(sheet), ); }); diff --git a/lib/sheetview.dart b/lib/sheetview.dart index 10c833f..f4370d5 100644 --- a/lib/sheetview.dart +++ b/lib/sheetview.dart @@ -1,36 +1,63 @@ import 'package:flutter/material.dart'; import 'package:pdfx/pdfx.dart'; +import 'package:sheetless/api.dart'; import 'package:sheetless/sheet.dart'; class SheetViewerPage extends StatefulWidget { final Sheet sheet; + final ApiClient apiClient; - const SheetViewerPage({super.key, required this.sheet}); + const SheetViewerPage( + {super.key, required this.sheet, required this.apiClient}); @override State createState() => _SheetViewerPageState(); } class _SheetViewerPageState extends State { - PdfController? controller; - @override void initState() { - controller = - PdfController(document: PdfDocument.openFile(widget.sheet.path)); super.initState(); } + Future loadPdf() async { + var file = await widget.apiClient.getPdfFileCached(widget.sheet.uuid); + if (file == null) { + throw Exception("Failed fetching pdf file"); + } + + return PdfController(document: PdfDocument.openFile(file.path)); + } + @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(widget.sheet.name), - ), - body: PdfView( - controller: controller!, - pageSnapping: false, - scrollDirection: Axis.vertical, - )); + appBar: AppBar( + title: Text(widget.sheet.name), + ), + body: FutureBuilder( + future: loadPdf(), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return PdfView( + controller: snapshot.data!, + pageSnapping: false, + scrollDirection: Axis.vertical, + ); + } else if (snapshot.hasError) { + return Center( + child: Text( + style: Theme.of(context) + .textTheme + .displaySmall! + .copyWith(color: Colors.red), + textAlign: TextAlign.center, + snapshot.error.toString())); + } else { + return const Center(child: CircularProgressIndicator()); + } + }), + ); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 0e67812..e689288 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,14 @@ import FlutterMacOS import Foundation -import device_info_plus_macos +import device_info_plus +import path_provider_foundation import pdfx +import sqflite_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PdfxPlugin.register(with: registry.registrar(forPlugin: "PdfxPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 48f3c9f..60072ca 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: @@ -37,82 +37,50 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.8" device_info_plus: dependency: transitive description: name: device_info_plus - sha256: b809c4ed5f7fcdb325ccc70b80ad934677dc4e2aa414bf46859a42bfdfafcbb6 + sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 url: "https://pub.dev" source: hosted - version: "4.1.3" - device_info_plus_linux: - dependency: transitive - description: - name: device_info_plus_linux - sha256: "77a8b3c4af06bc46507f89304d9f49dfc64b4ae004b994532ed23b34adeae4b3" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - device_info_plus_macos: - dependency: transitive - description: - name: device_info_plus_macos - sha256: "37961762fbd46d3620c7b69ca606671014db55fc1b7a11e696fd90ed2e8fe03d" - url: "https://pub.dev" - source: hosted - version: "3.0.0" + version: "10.1.2" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "83fdba24fcf6846d3b10f10dfdc8b6c6d7ada5f8ed21d62ea2909c2dfa043773" + sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" url: "https://pub.dev" source: hosted - version: "3.0.0" - device_info_plus_web: - dependency: transitive - description: - name: device_info_plus_web - sha256: "5890f6094df108181c7a29720bc23d0fd6159f17d82787fac093d1fefcaf6325" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - device_info_plus_windows: - dependency: transitive - description: - name: device_info_plus_windows - sha256: "23a2874af0e23ee6e3a2a0ebcecec3a9da13241f2cb93a93a44c8764df123dd7" - url: "https://pub.dev" - source: hosted - version: "4.1.0" + version: "7.0.2" extension: dependency: transitive description: name: extension - sha256: "7df1ee2de6ccd05fd3e4d63acb194ae97e6525a2e8da067161c0cccb6a0a5305" + sha256: be3a6b7f8adad2f6e2e8c63c895d19811fcf203e23466c6296267941d0ff4f24 url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.6.0" fake_async: dependency: transitive description: @@ -125,31 +93,47 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: "direct main" + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "5.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -160,118 +144,214 @@ packages: description: flutter source: sdk version: "0.0.0" - js: - dependency: transitive + http: + dependency: "direct main" description: - name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "1.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "5.0.0" matcher: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.15.0" path: dependency: "direct main" description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.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: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + url: "https://pub.dev" + source: hosted + version: "2.2.15" + 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: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" pdfx: dependency: "direct main" description: name: pdfx - sha256: cad7eab6358a89922c8ea592b738891b3984edab43300558d25dc9b15a94a35e + sha256: cbbd7bf54d6f37524df85d06a816fa095d124cd32d42909effddc0027f9db10b url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.8.0" permission_handler: dependency: "direct main" description: name: permission_handler - sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + sha256: bc56bfe9d3f44c3c612d8d393bd9b174eb796d706759f9b495ac254e4294baa5 url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.4.5" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" + sha256: "59c6322171c29df93a22d150ad95f3aa19ed86542eaec409ab2691b8f35f9a47" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.3.6" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" + sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5" url: "https://pub.dev" source: hosted - version: "9.0.7" + version: "9.1.4" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4" url: "https://pub.dev" source: hosted - version: "3.9.0" + version: "3.12.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "0.1.3" photo_view: dependency: transitive description: name: photo_view - sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb" + sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" url: "https://pub.dev" source: hosted - version: "0.14.0" + version: "0.15.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.8" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" saf: dependency: "direct main" description: @@ -289,26 +369,74 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" + url: "https://pub.dev" + source: hosted + version: "2.5.4+6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -321,10 +449,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" + sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.3.0+3" term_glyph: dependency: transitive description: @@ -337,34 +465,34 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.7.2" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" universal_platform: dependency: transitive description: name: universal_platform - sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" url: "https://pub.dev" source: hosted - version: "1.0.0+1" + version: "1.1.0" uuid: dependency: transitive description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.5.1" vector_math: dependency: transitive description: @@ -373,14 +501,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" win32: dependency: transitive description: name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "5.9.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" + url: "https://pub.dev" + source: hosted + version: "1.1.5" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" sdks: - dart: ">=2.19.2 <3.0.0" - flutter: ">=3.0.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index ba9187c..c3db8fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,9 @@ dependencies: pdfx: ^2.3.0 saf: ^1.0.3+4 permission_handler: ^10.2.0 + http: ^1.2.2 + path_provider: ^2.1.5 + flutter_cache_manager: ^3.4.1 dev_dependencies: flutter_test: @@ -50,7 +53,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^2.0.0 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/web/index.html b/web/index.html index ee4d315..d50d70c 100644 --- a/web/index.html +++ b/web/index.html @@ -31,29 +31,18 @@ sheetless - - - - - + +