Work on implementing sheetable client

This commit is contained in:
2024-12-18 00:36:33 +01:00
parent 0825f048cd
commit f530a52e9d
8 changed files with 620 additions and 209 deletions

206
lib/api.dart Normal file
View File

@@ -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<bool> 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<http.Response?> 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<http.Response?> post(
String endpoint, Map<String, dynamic> 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<http.Response?> 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<List<Sheet>> 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<dynamic>)
.map((sheet) => Sheet.fromJson(sheet as Map<String, dynamic>))
.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<File?> 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;
}
}

View File

@@ -1,8 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:saf/saf.dart'; import 'package:saf/saf.dart';
import 'package:sheetless/sheetview.dart'; import 'package:sheetless/sheetview.dart';
import 'package:path_provider/path_provider.dart';
import 'api.dart';
import 'sheet.dart'; import 'sheet.dart';
void main() { void main() {
@@ -33,38 +34,53 @@ class MyHomePage extends StatefulWidget {
} }
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
ApiClient apiClient = ApiClient();
Future<bool> apiLoggedIn = Future.value(false);
@override @override
void initState() { void initState() {
super.initState(); super.initState();
apiLoggedIn = apiClient.login("admin@admin.com", "sheetable");
} }
Future<String?> getSafPickedSheetsDirectory() async { // Future<String?> getSafPickedSheetsDirectory() async {
await Permission.storage.request(); // await Permission.storage.request();
await Permission.manageExternalStorage.request(); // await Permission.manageExternalStorage.request();
var pickedDirectories = await Saf.getPersistedPermissionDirectories(); // var pickedDirectories = await Saf.getPersistedPermissionDirectories();
if (pickedDirectories == null || pickedDirectories.isEmpty) { // if (pickedDirectories == null || pickedDirectories.isEmpty) {
return null; // return null;
} // }
return pickedDirectories.last; // return pickedDirectories.last;
} // }
Future<List<Sheet>> acquireSheets() async { Future<List<Sheet>> acquireSheets() async {
String? sheetsDirectory = await getSafPickedSheetsDirectory(); // await Permission.storage.request();
if (sheetsDirectory == null || sheetsDirectory.isEmpty) { // await Permission.manageExternalStorage.request();
await Saf.getDynamicDirectoryPermission(grantWritePermission: false); //
sheetsDirectory = await getSafPickedSheetsDirectory();
if (sheetsDirectory == null || sheetsDirectory.isEmpty) {
throw Exception("No Directory selected");
}
}
var sheetsDirectoryFiles = await Saf.getFilesPathFor(sheetsDirectory); await apiLoggedIn; // TODO: check if really logged in (returns bool)
if (sheetsDirectoryFiles == null) { return await apiClient.fetchSheets();
await Saf.releasePersistedPermissions(); // return api.main();
throw Exception(
"Permissions for directory no longer valid or Directory deleted. Please restart app."); // final directory = await getApplicationDocumentsDirectory();
} // print("Directory is: $directory");
return loadSheetsSorted(sheetsDirectoryFiles); // 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 @override
@@ -82,7 +98,10 @@ class _MyHomePageState extends State<MyHomePage> {
callback: (sheet) => Navigator.push( callback: (sheet) => Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => SheetViewerPage(sheet: sheet), builder: (context) => SheetViewerPage(
sheet: sheet,
apiClient: apiClient,
),
), ),
), ),
); );

View File

@@ -4,50 +4,53 @@ import 'package:flutter/material.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
class Sheet { class Sheet {
final String author; final String uuid;
final String name; 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<String> 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<List<Sheet>> loadSheetsSorted(List<String> sheetsDirectoryFiles) async { // Factory constructor for creating a Sheet from JSON
var sheets = await _loadSheets(sheetsDirectoryFiles); factory Sheet.fromJson(Map<String, dynamic> json) {
sheets.sort((left, right) => left.name.compareTo(right.name)); return Sheet(
return sheets; uuid: json['uuid'],
} name: json['sheet_name'],
composerUuid: json['composer_uuid'],
Future<List<Sheet>> _loadSheets(List<String> sheetsDirectoryFiles) async { releaseDate: DateTime.parse(json['release_date']),
final List<Sheet> sheets = List.empty(growable: true); file: json['file'],
var authorDirectories = sheetsDirectoryFiles fileHash: json['file_hash'],
.map((e) => Directory(e)) wasUploaded: json['was_uploaded'],
.where((element) => element.existsSync()); uploaderId: json['uploader_id'],
createdAt: DateTime.parse(json['created_at']),
for (Directory authorDirectory in authorDirectories) { updatedAt: DateTime.parse(json['updated_at']),
var authorName = p.basename(authorDirectory.path); lastOpened: DateTime.parse(json['last_opened']),
// Ignore hidden directories tags: List<String>.from(json['tags']),
if (authorName.startsWith(".")) { informationText: json['information_text'],
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()}";
} }
} }
@@ -65,7 +68,7 @@ class SheetsWidget extends StatelessWidget {
var sheet = sheets[index]; var sheet = sheets[index];
return ListTile( return ListTile(
title: Text(sheet.name), title: Text(sheet.name),
subtitle: Text(sheet.author), subtitle: Text(sheet.uuid),
onTap: () => callback(sheet), onTap: () => callback(sheet),
); );
}); });

View File

@@ -1,36 +1,63 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pdfx/pdfx.dart'; import 'package:pdfx/pdfx.dart';
import 'package:sheetless/api.dart';
import 'package:sheetless/sheet.dart'; import 'package:sheetless/sheet.dart';
class SheetViewerPage extends StatefulWidget { class SheetViewerPage extends StatefulWidget {
final Sheet sheet; final Sheet sheet;
final ApiClient apiClient;
const SheetViewerPage({super.key, required this.sheet}); const SheetViewerPage(
{super.key, required this.sheet, required this.apiClient});
@override @override
State<SheetViewerPage> createState() => _SheetViewerPageState(); State<SheetViewerPage> createState() => _SheetViewerPageState();
} }
class _SheetViewerPageState extends State<SheetViewerPage> { class _SheetViewerPageState extends State<SheetViewerPage> {
PdfController? controller;
@override @override
void initState() { void initState() {
controller =
PdfController(document: PdfDocument.openFile(widget.sheet.path));
super.initState(); super.initState();
} }
Future<PdfController> 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(widget.sheet.name), title: Text(widget.sheet.name),
), ),
body: PdfView( body: FutureBuilder(
controller: controller!, future: loadPdf(),
pageSnapping: false, builder:
scrollDirection: Axis.vertical, (BuildContext context, AsyncSnapshot<PdfController> 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());
}
}),
);
} }
} }

View File

@@ -5,10 +5,14 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import device_info_plus_macos import device_info_plus
import path_provider_foundation
import pdfx import pdfx
import sqflite_darwin
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PdfxPlugin.register(with: registry.registrar(forPlugin: "PdfxPlugin")) PdfxPlugin.register(with: registry.registrar(forPlugin: "PdfxPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
} }

View File

@@ -5,10 +5,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.11.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@@ -21,10 +21,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@@ -37,82 +37,50 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.18.0"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.6"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
name: cupertino_icons name: cupertino_icons
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.5" version: "1.0.8"
device_info_plus: device_info_plus:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus name: device_info_plus
sha256: b809c4ed5f7fcdb325ccc70b80ad934677dc4e2aa414bf46859a42bfdfafcbb6 sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.3" version: "10.1.2"
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"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_platform_interface name: device_info_plus_platform_interface
sha256: "83fdba24fcf6846d3b10f10dfdc8b6c6d7ada5f8ed21d62ea2909c2dfa043773" sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "7.0.2"
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"
extension: extension:
dependency: transitive dependency: transitive
description: description:
name: extension name: extension
sha256: "7df1ee2de6ccd05fd3e4d63acb194ae97e6525a2e8da067161c0cccb6a0a5305" sha256: be3a6b7f8adad2f6e2e8c63c895d19811fcf203e23466c6296267941d0ff4f24
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.6.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@@ -125,31 +93,47 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.1.3"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" 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: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "5.0.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@@ -160,118 +144,214 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
js: http:
dependency: transitive dependency: "direct main"
description: description:
name: js name: http
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: lints:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "5.0.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.13" version: "0.12.16+1"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.0" version: "0.11.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.15.0"
path: path:
dependency: "direct main" dependency: "direct main"
description: description:
name: path name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: pdfx:
dependency: "direct main" dependency: "direct main"
description: description:
name: pdfx name: pdfx
sha256: cad7eab6358a89922c8ea592b738891b3984edab43300558d25dc9b15a94a35e sha256: cbbd7bf54d6f37524df85d06a816fa095d124cd32d42909effddc0027f9db10b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.8.0"
permission_handler: permission_handler:
dependency: "direct main" dependency: "direct main"
description: description:
name: permission_handler name: permission_handler
sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" sha256: bc56bfe9d3f44c3c612d8d393bd9b174eb796d706759f9b495ac254e4294baa5
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.2.0" version: "10.4.5"
permission_handler_android: permission_handler_android:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_android name: permission_handler_android
sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" sha256: "59c6322171c29df93a22d150ad95f3aa19ed86542eaec409ab2691b8f35f9a47"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.2.0" version: "10.3.6"
permission_handler_apple: permission_handler_apple:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_apple name: permission_handler_apple
sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.0.7" version: "9.1.4"
permission_handler_platform_interface: permission_handler_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_platform_interface name: permission_handler_platform_interface
sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.9.0" version: "3.12.0"
permission_handler_windows: permission_handler_windows:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_windows name: permission_handler_windows
sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.2" version: "0.1.3"
photo_view: photo_view:
dependency: transitive dependency: transitive
description: description:
name: photo_view name: photo_view
sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb" sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: saf:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -289,26 +369,74 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.11.1"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
@@ -321,10 +449,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: synchronized name: synchronized
sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.3.0+3"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@@ -337,34 +465,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.16" version: "0.7.2"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.4.0"
universal_platform: universal_platform:
dependency: transitive dependency: transitive
description: description:
name: universal_platform name: universal_platform
sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0+1" version: "1.1.0"
uuid: uuid:
dependency: transitive dependency: transitive
description: description:
name: uuid name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.7" version: "4.5.1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -373,14 +501,46 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" 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: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: sdks:
dart: ">=2.19.2 <3.0.0" dart: ">=3.5.0 <4.0.0"
flutter: ">=3.0.0" flutter: ">=3.24.0"

View File

@@ -40,6 +40,9 @@ dependencies:
pdfx: ^2.3.0 pdfx: ^2.3.0
saf: ^1.0.3+4 saf: ^1.0.3+4
permission_handler: ^10.2.0 permission_handler: ^10.2.0
http: ^1.2.2
path_provider: ^2.1.5
flutter_cache_manager: ^3.4.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -50,7 +53,7 @@ dev_dependencies:
# activated in the `analysis_options.yaml` file located at the root of your # activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint # package. See that file for information about deactivating specific lint
# rules and activating additional ones. # 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 # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec

View File

@@ -31,29 +31,18 @@
<title>sheetless</title> <title>sheetless</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
<script>
// The value below is injected by flutter build, do not touch.
var serviceWorkerVersion = null;
</script>
<!-- This script adds the flutter initialization JS code -->
<script src="flutter.js" defer></script>
</head> </head>
<body> <body>
<script> <script src='https://cdn.jsdelivr.net/npm/pdfjs-dist@4.6.82/build/pdf.min.mjs' type='module'></script>
window.addEventListener('load', function(ev) { <script type='module'>
// Download main.dart.js var { pdfjsLib } = globalThis;
_flutter.loader.loadEntrypoint({ pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.6.82/build/pdf.worker.mjs';
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion, var pdfRenderOptions = {
}, cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.6.82/cmaps/',
onEntrypointLoaded: function(engineInitializer) { cMapPacked: true,
engineInitializer.initializeEngine().then(function(appRunner) { }
appRunner.runApp();
});
}
});
});
</script> </script>
<script src="flutter_bootstrap.js" async></script>
</body> </body>
</html> </html>