Add functional login page
This commit is contained in:
70
lib/api.dart
70
lib/api.dart
@@ -1,24 +1,21 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:path_provider/path_provider.dart'; // For cache storage
|
import 'package:path_provider/path_provider.dart'; // For cache storage
|
||||||
import 'package:file/memory.dart';
|
|
||||||
|
|
||||||
import 'sheet.dart';
|
import 'sheet.dart';
|
||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
final String baseUrl =
|
final String baseUrl;
|
||||||
'http://localhost:8080/api'; // Replace with your API base URL
|
String? token;
|
||||||
String? _token; // Holds the JWT token after login
|
|
||||||
|
|
||||||
/// Checks if the user is authenticated
|
ApiClient({required this.baseUrl, this.token});
|
||||||
bool get isAuthenticated => _token != null;
|
|
||||||
|
|
||||||
/// Login and store the JWT token
|
/// Login and store the JWT token
|
||||||
Future<bool> login(String username, String password) async {
|
Future<bool> login(String username, String password) async {
|
||||||
print("Logging in...");
|
log("Logging in...");
|
||||||
try {
|
try {
|
||||||
final url = '$baseUrl/login';
|
final url = '$baseUrl/login';
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
@@ -31,22 +28,22 @@ class ApiClient {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
_token = jsonDecode(response.body);
|
token = jsonDecode(response.body);
|
||||||
print('Login successful, token: $_token');
|
log('Login successful');
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
print('Login failed: ${response.statusCode}, ${response.body}');
|
log('Login failed: ${response.statusCode}, ${response.body}');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error during login: $e');
|
log('Error during login: $e');
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Logout and clear the token
|
/// Logout and clear the token
|
||||||
void logout() {
|
void logout() {
|
||||||
_token = null;
|
token = null;
|
||||||
print('Logged out successfully.');
|
log('Logged out successfully.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make a GET request
|
/// Make a GET request
|
||||||
@@ -54,7 +51,7 @@ class ApiClient {
|
|||||||
try {
|
try {
|
||||||
final url = '$baseUrl$endpoint';
|
final url = '$baseUrl$endpoint';
|
||||||
final headers = {
|
final headers = {
|
||||||
'Authorization': 'Bearer $_token',
|
'Authorization': 'Bearer $token',
|
||||||
if (!isBinary) 'Content-Type': 'application/json',
|
if (!isBinary) 'Content-Type': 'application/json',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,10 +60,10 @@ class ApiClient {
|
|||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
print('GET request failed: ${response.statusCode} ${response.body}');
|
log('GET request failed: ${response.statusCode} ${response.body}');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error during GET request: $e');
|
log('Error during GET request: $e');
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -77,7 +74,7 @@ class ApiClient {
|
|||||||
try {
|
try {
|
||||||
final url = '$baseUrl$endpoint';
|
final url = '$baseUrl$endpoint';
|
||||||
final headers = {
|
final headers = {
|
||||||
'Authorization': 'Bearer $_token',
|
'Authorization': 'Bearer $token',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,10 +87,10 @@ class ApiClient {
|
|||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
print('POST request failed: ${response.statusCode} ${response.body}');
|
log('POST request failed: ${response.statusCode} ${response.body}');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error during POST request: $e');
|
log('Error during POST request: $e');
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -103,7 +100,7 @@ class ApiClient {
|
|||||||
try {
|
try {
|
||||||
final url = '$baseUrl$endpoint';
|
final url = '$baseUrl$endpoint';
|
||||||
final headers = {
|
final headers = {
|
||||||
'Authorization': 'Bearer $_token',
|
'Authorization': 'Bearer $token',
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,11 +113,10 @@ class ApiClient {
|
|||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
print(
|
log('POST Form Data request failed: ${response.statusCode} ${response.body}');
|
||||||
'POST Form Data request failed: ${response.statusCode} ${response.body}');
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error during POST Form Data request: $e');
|
log('Error during POST Form Data request: $e');
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -133,27 +129,24 @@ class ApiClient {
|
|||||||
"sort_by": sortBy,
|
"sort_by": sortBy,
|
||||||
};
|
};
|
||||||
|
|
||||||
print("doing post...");
|
|
||||||
final response = await postFormData("/sheets", jsonEncode(bodyFormData));
|
final response = await postFormData("/sheets", jsonEncode(bodyFormData));
|
||||||
print("got response...");
|
|
||||||
|
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
print("Empty reponse");
|
|
||||||
return List.empty();
|
return List.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = jsonDecode(response.body);
|
final data = jsonDecode(response.body);
|
||||||
print("Data: $data");
|
log("Data: $data");
|
||||||
return (data['rows'] as List<dynamic>)
|
return (data['rows'] as List<dynamic>)
|
||||||
.map((sheet) => Sheet.fromJson(sheet as Map<String, dynamic>))
|
.map((sheet) => Sheet.fromJson(sheet as Map<String, dynamic>))
|
||||||
.toList();
|
.toList();
|
||||||
} else {
|
} else {
|
||||||
print('Failed to fetch sheets with status: ${response.statusCode}');
|
log('Failed to fetch sheets with status: ${response.statusCode}');
|
||||||
print('Response: ${response.body}');
|
log('Response: ${response.body}');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error during fetching sheets: $e');
|
log('Error during fetching sheets: $e');
|
||||||
}
|
}
|
||||||
|
|
||||||
return List.empty();
|
return List.empty();
|
||||||
@@ -163,42 +156,35 @@ class ApiClient {
|
|||||||
try {
|
try {
|
||||||
// Get the cache directory
|
// Get the cache directory
|
||||||
|
|
||||||
print("Creating cache dir...");
|
|
||||||
// final cacheDir = kIsWeb
|
// final cacheDir = kIsWeb
|
||||||
// ? await MemoryFileSystem().systemTempDirectory.createTemp('cache')
|
// ? await MemoryFileSystem().systemTempDirectory.createTemp('cache')
|
||||||
// : await getTemporaryDirectory();
|
// : await getTemporaryDirectory();
|
||||||
final cacheDir = await getTemporaryDirectory();
|
final cacheDir = await getTemporaryDirectory();
|
||||||
final cachedPdfPath = '${cacheDir.path}/$sheetUuid.pdf';
|
final cachedPdfPath = '${cacheDir.path}/$sheetUuid.pdf';
|
||||||
|
|
||||||
print("cache dir created");
|
|
||||||
|
|
||||||
// Check if the file already exists in the cache
|
// Check if the file already exists in the cache
|
||||||
final cachedFile = File(cachedPdfPath);
|
final cachedFile = File(cachedPdfPath);
|
||||||
|
|
||||||
print("file created: $cachedFile");
|
|
||||||
if (await cachedFile.exists()) {
|
if (await cachedFile.exists()) {
|
||||||
print("PDF found in cache: $cachedPdfPath");
|
log("PDF found in cache: $cachedPdfPath");
|
||||||
return cachedFile;
|
return cachedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the authenticated API call
|
// Make the authenticated API call
|
||||||
|
|
||||||
print("getting response");
|
|
||||||
final response = await this.get('/sheet/pdf/$sheetUuid', isBinary: true);
|
final response = await this.get('/sheet/pdf/$sheetUuid', isBinary: true);
|
||||||
|
|
||||||
print("got response");
|
|
||||||
if (response != null && response.statusCode == 200) {
|
if (response != null && response.statusCode == 200) {
|
||||||
// Save the fetched file to the cache
|
// Save the fetched file to the cache
|
||||||
//
|
//
|
||||||
print("writing file...: $cachedFile");
|
|
||||||
await cachedFile.writeAsBytes(response.bodyBytes);
|
await cachedFile.writeAsBytes(response.bodyBytes);
|
||||||
print("PDF downloaded and cached at: $cachedPdfPath");
|
log("PDF downloaded and cached at: $cachedPdfPath");
|
||||||
return cachedFile;
|
return cachedFile;
|
||||||
} else {
|
} else {
|
||||||
print("Failed to fetch PDF from API. Status: ${response?.statusCode}");
|
log("Failed to fetch PDF from API. Status: ${response?.statusCode}");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error fetching PDF: $e");
|
log("Error fetching PDF: $e");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
101
lib/home_page.dart
Normal file
101
lib/home_page.dart
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:sheetless/sheetview.dart';
|
||||||
|
import 'package:sheetless/storage_helper.dart';
|
||||||
|
|
||||||
|
import 'api.dart';
|
||||||
|
import 'sheet.dart';
|
||||||
|
|
||||||
|
class MyHomePage extends StatefulWidget {
|
||||||
|
const MyHomePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MyHomePage> createState() => _MyHomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
|
ApiClient? apiClient;
|
||||||
|
Future<bool> apiLoggedIn = Future.value(false);
|
||||||
|
final StorageHelper _storageHelper = StorageHelper();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Future<String?> 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<List<Sheet>> acquireSheets() async {
|
||||||
|
final url = await _storageHelper.read(StorageKey.url);
|
||||||
|
final jwt = await _storageHelper.read(StorageKey.jwt);
|
||||||
|
apiClient = ApiClient(baseUrl: url!, token: jwt);
|
||||||
|
// TODO: check if really logged in
|
||||||
|
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
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text("My Sheets"),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: acquireSheets(),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<List<Sheet>> snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
return SheetsWidget(
|
||||||
|
sheets: snapshot.data!,
|
||||||
|
callback: (sheet) => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => SheetViewerPage(
|
||||||
|
sheet: sheet,
|
||||||
|
apiClient: apiClient!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} 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());
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
lib/login.dart
Normal file
1
lib/login.dart
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
125
lib/login_page.dart
Normal file
125
lib/login_page.dart
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:jwt_decoder/jwt_decoder.dart';
|
||||||
|
import 'package:sheetless/api.dart';
|
||||||
|
import 'package:sheetless/home_page.dart';
|
||||||
|
import 'package:sheetless/storage_helper.dart';
|
||||||
|
|
||||||
|
class LoginPage extends StatefulWidget {
|
||||||
|
const LoginPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_LoginPageState createState() => _LoginPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LoginPageState extends State<LoginPage> {
|
||||||
|
final TextEditingController _urlController = TextEditingController();
|
||||||
|
final TextEditingController _emailController = TextEditingController();
|
||||||
|
final TextEditingController _passwordController = TextEditingController();
|
||||||
|
|
||||||
|
final StorageHelper _storageHelper = StorageHelper();
|
||||||
|
String? _error;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_checkJwtValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _checkJwtValidity() async {
|
||||||
|
final jwt = await _storageHelper.read(StorageKey.jwt);
|
||||||
|
if (jwt != null) {
|
||||||
|
final isValid = await _validateJwt(jwt);
|
||||||
|
if (isValid) {
|
||||||
|
_navigateToMainPage();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
final url = await _storageHelper.read(StorageKey.url);
|
||||||
|
final email = await _storageHelper.read(StorageKey.email);
|
||||||
|
final password = await _storageHelper.read(StorageKey.password);
|
||||||
|
if (url != null && email != null && password != null) {
|
||||||
|
_login(url, email, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _validateJwt(String jwt) async {
|
||||||
|
try {
|
||||||
|
bool expired = JwtDecoder.isExpired(jwt);
|
||||||
|
return !expired;
|
||||||
|
} on FormatException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _login(String serverUrl, String email, String password) async {
|
||||||
|
setState(() {
|
||||||
|
_error = null;
|
||||||
|
});
|
||||||
|
final apiClient = ApiClient(baseUrl: serverUrl);
|
||||||
|
final loginSuccessful = await apiClient.login(email, password);
|
||||||
|
if (loginSuccessful) {
|
||||||
|
await _storageHelper.write(StorageKey.url, serverUrl);
|
||||||
|
await _storageHelper.write(StorageKey.jwt, apiClient.token!);
|
||||||
|
await _storageHelper.write(StorageKey.email, email);
|
||||||
|
await _storageHelper.write(StorageKey.password, password);
|
||||||
|
_navigateToMainPage();
|
||||||
|
} else {
|
||||||
|
// TODO: give more varied error messages
|
||||||
|
setState(() {
|
||||||
|
_error = "Login failed.";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _navigateToMainPage() {
|
||||||
|
Navigator.of(context).pushReplacement(
|
||||||
|
MaterialPageRoute(builder: (_) => MyHomePage()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(title: Text('Login')),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
controller: _urlController,
|
||||||
|
decoration: InputDecoration(labelText: 'Url'),
|
||||||
|
),
|
||||||
|
TextField(
|
||||||
|
controller: _emailController,
|
||||||
|
decoration: InputDecoration(labelText: 'Email'),
|
||||||
|
),
|
||||||
|
TextField(
|
||||||
|
controller: _passwordController,
|
||||||
|
decoration: InputDecoration(labelText: 'Password'),
|
||||||
|
obscureText: true,
|
||||||
|
),
|
||||||
|
if (_error != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Text(_error!, style: TextStyle(color: Colors.red)),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
_login(_urlController.text, _emailController.text,
|
||||||
|
_passwordController.text);
|
||||||
|
},
|
||||||
|
child: Text('Login'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
104
lib/main.dart
104
lib/main.dart
@@ -1,10 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:saf/saf.dart';
|
|
||||||
import 'package:sheetless/sheetview.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
import 'api.dart';
|
import 'login_page.dart';
|
||||||
import 'sheet.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@@ -21,103 +17,7 @@ class MyApp extends StatelessWidget {
|
|||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
primarySwatch: Colors.blue,
|
primarySwatch: Colors.blue,
|
||||||
),
|
),
|
||||||
home: const MyHomePage(),
|
home: const LoginPage(),
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
|
||||||
const MyHomePage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MyHomePage> createState() => _MyHomePageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
|
||||||
ApiClient apiClient = ApiClient();
|
|
||||||
Future<bool> apiLoggedIn = Future.value(false);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
apiLoggedIn = apiClient.login("admin@admin.com", "sheetable");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Future<String?> 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<List<Sheet>> acquireSheets() async {
|
|
||||||
// await Permission.storage.request();
|
|
||||||
// await Permission.manageExternalStorage.request();
|
|
||||||
//
|
|
||||||
|
|
||||||
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
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text("My Sheets"),
|
|
||||||
),
|
|
||||||
body: FutureBuilder(
|
|
||||||
future: acquireSheets(),
|
|
||||||
builder: (BuildContext context, AsyncSnapshot<List<Sheet>> snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return SheetsWidget(
|
|
||||||
sheets: snapshot.data!,
|
|
||||||
callback: (sheet) => Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => SheetViewerPage(
|
|
||||||
sheet: sheet,
|
|
||||||
apiClient: apiClient,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} 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());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
lib/storage_helper.dart
Normal file
22
lib/storage_helper.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
|
||||||
|
enum StorageKey { url, jwt, email, password }
|
||||||
|
|
||||||
|
class StorageHelper {
|
||||||
|
late FlutterSecureStorage secureStorage;
|
||||||
|
|
||||||
|
StorageHelper() {
|
||||||
|
AndroidOptions getAndroidOptions() => const AndroidOptions(
|
||||||
|
encryptedSharedPreferences: true,
|
||||||
|
);
|
||||||
|
secureStorage = FlutterSecureStorage(aOptions: getAndroidOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> read(StorageKey key) {
|
||||||
|
return secureStorage.read(key: key.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> write(StorageKey key, String value) {
|
||||||
|
return secureStorage.write(key: key.name, value: value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||||
|
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
flutter_secure_storage_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
|
import flutter_secure_storage_macos
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import pdfx
|
import pdfx
|
||||||
import sqflite_darwin
|
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"))
|
||||||
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
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"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
|
|||||||
64
pubspec.lock
64
pubspec.lock
@@ -134,6 +134,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.0"
|
||||||
|
flutter_secure_storage:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_secure_storage
|
||||||
|
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.2.2"
|
||||||
|
flutter_secure_storage_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_secure_storage_linux
|
||||||
|
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
flutter_secure_storage_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_secure_storage_macos
|
||||||
|
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
|
flutter_secure_storage_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_secure_storage_platform_interface
|
||||||
|
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
flutter_secure_storage_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_secure_storage_web
|
||||||
|
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
flutter_secure_storage_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_secure_storage_windows
|
||||||
|
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -160,6 +208,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.7"
|
||||||
|
jwt_decoder:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: jwt_decoder
|
||||||
|
sha256: "54774aebf83f2923b99e6416b4ea915d47af3bde56884eb622de85feabbc559f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ dependencies:
|
|||||||
http: ^1.2.2
|
http: ^1.2.2
|
||||||
path_provider: ^2.1.5
|
path_provider: ^2.1.5
|
||||||
flutter_cache_manager: ^3.4.1
|
flutter_cache_manager: ^3.4.1
|
||||||
|
flutter_secure_storage: ^9.2.2
|
||||||
|
jwt_decoder: ^2.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -6,10 +6,13 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||||
#include <pdfx/pdfx_plugin.h>
|
#include <pdfx/pdfx_plugin.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||||
PdfxPluginRegisterWithRegistrar(
|
PdfxPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PdfxPlugin"));
|
registry->GetRegistrarForPlugin("PdfxPlugin"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
flutter_secure_storage_windows
|
||||||
pdfx
|
pdfx
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user