fix: resolve Sheetifye Excel viewer integration, Riverpod autoDispose type bounds, and Dashboard initState error

This commit is contained in:
ssbg04 committed 2026-08-18 10:30:34 +08:00
1 parent 93f419f6d1
commit db42cf3050
11 files changed
+78 -635

No files matched your search

+5 -2
View File
@@ -158,9 +158,12 @@ Files backup/restore - mirror mode or zip -->
- Document preveiew modal -> make it fullscreen modal -> add "add to print list" icon button -> move the zoom in/out inside of the pdf or image viewer -> add "open with" icon button for excel files to open external excel viewer
- hold feature to see more menu in android add "view student profile" -->
# ARCHVES SCREEN
<!-- # ARCHVES SCREEN
- From "DOCUMENTS SCREEN", add hold feature for android and right click for windows to see more menu, add multi select and its multi select menu, and FAB print list for android, button print list for windows
- fix grid view in all archived docs tab
- fix grid view in all archived docs tab -->
# DOCUMENTS SCREEN
- document preview modal -> use sheetifye package for excel viewer
---
@@ -49,7 +49,8 @@ final userHistoryQueryProvider =
UserHistoryQueryParams
>(UserHistoryQueryNotifier.new);
class UserHistoryQueryNotifier extends Notifier<UserHistoryQueryParams> {
class UserHistoryQueryNotifier
extends AutoDisposeNotifier<UserHistoryQueryParams> {
@override
UserHistoryQueryParams build() => const UserHistoryQueryParams();
+1 -6
View File
@@ -5,13 +5,8 @@ import '../../domain/entities/user_model.dart';
import 'document_provider.dart';
import 'archives_provider.dart';
import 'student_provider.dart' hide academicYearsProvider;
import 'users_provider.dart';
import 'notification_provider.dart';
import 'navigation_provider.dart';
import 'dashboard_provider.dart';
import 'setup_provider.dart';
import 'reports_provider.dart';
import 'ocr_provider.dart';
import 'connected_users_provider.dart';
final authRepositoryProvider = Provider<AuthRepository>(
@@ -102,7 +97,7 @@ class AuthNotifier extends AsyncNotifier<UserModel?> {
final repository = ref.read(authRepositoryProvider);
final updatedUser = await repository.getProfile();
state = AsyncData(updatedUser);
} catch (e, stack) {
} catch (e) {
// Don't emit error state to prevent UI disruptions on background refresh failures
print('Background refresh failed: $e');
}
@@ -94,7 +94,7 @@ final activityQueryProvider =
ActivityQueryNotifier.new,
);
class ActivityQueryNotifier extends Notifier<ActivityQueryParams> {
class ActivityQueryNotifier extends AutoDisposeNotifier<ActivityQueryParams> {
@override
ActivityQueryParams build() => const ActivityQueryParams();
@@ -62,10 +62,9 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
if (mounted) setState(() {});
});
ref.invalidate(dashboardDataProvider);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
ref.invalidate(dashboardDataProvider);
ref.read(notificationsProvider.notifier).refreshNotifications();
if (ref.read(activeTabProvider) == 'Dashboard') {
@@ -107,23 +107,26 @@ class _DocumentsScreenState extends ConsumerState<DocumentsScreen>
}
});
// If a specific student was passed, jump to Folders tab and open that folder
final initialFolder = ref.read(openedFolderProvider);
if (initialFolder != null) {
_openedFolderStudentId = initialFolder.id;
_openedFolderName = initialFolder.name;
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
// If a specific student was passed, jump to Folders tab and open that folder
final initialFolder = ref.read(openedFolderProvider);
if (initialFolder != null) {
setState(() {
_openedFolderStudentId = initialFolder.id;
_openedFolderName = initialFolder.name;
});
ref.read(documentQueryProvider.notifier).setStudentId(initialFolder.id);
});
} else if (widget.initialStudentId != null) {
_openedFolderStudentId = widget.initialStudentId;
_openedFolderName = 'Student Documents';
WidgetsBinding.instance.addPostFrameCallback((_) {
} else if (widget.initialStudentId != null) {
setState(() {
_openedFolderStudentId = widget.initialStudentId;
_openedFolderName = 'Student Documents';
});
ref
.read(documentQueryProvider.notifier)
.setStudentId(widget.initialStudentId);
});
}
}
});
_tabController.addListener(() {
setState(() {}); // Ensure header title updates immediately on tab change
@@ -61,7 +61,6 @@ class _DocumentPreviewDialog extends ConsumerStatefulWidget {
class _DocumentPreviewDialogState
extends ConsumerState<_DocumentPreviewDialog> {
bool _imageError = false;
bool _imageLoaded = false;
String? _token;
bool _isOpeningExternal = false;
@@ -71,13 +70,13 @@ class _DocumentPreviewDialogState
void _zoomImageIn() {
final matrix = _imageTransformationController.value.clone();
matrix.scale(1.25, 1.25, 1.0);
matrix.scaleByDouble(1.25, 1.25, 1.0, 1.0);
_imageTransformationController.value = matrix;
}
void _zoomImageOut() {
final matrix = _imageTransformationController.value.clone();
matrix.scale(1 / 1.25, 1 / 1.25, 1.0);
matrix.scaleByDouble(1 / 1.25, 1 / 1.25, 1.0, 1.0);
_imageTransformationController.value = matrix;
}
@@ -93,9 +92,6 @@ class _DocumentPreviewDialogState
@override
void initState() {
super.initState();
if (widget.localFile != null) {
_imageLoaded = true;
}
_loadToken();
}
@@ -447,16 +443,7 @@ class _DocumentPreviewDialogState
_fileUrl,
fit: BoxFit.contain,
loadingBuilder: (ctx, child, progress) {
if (progress == null) {
WidgetsBinding.instance.addPostFrameCallback((
_,
) {
if (mounted) {
setState(() => _imageLoaded = true);
}
});
return child;
}
if (progress == null) return child;
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
@@ -480,7 +467,7 @@ class _DocumentPreviewDialogState
),
);
},
errorBuilder: (_, __, ___) {
errorBuilder: (context, error, stackTrace) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) setState(() => _imageError = true);
});
@@ -1,100 +1,11 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:excel/excel.dart' hide Border;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:sheetifye/sheetifye.dart';
import '../../../../core/constants/app_colors.dart';
/// Background isolate function to decode CSV bytes without blocking UI thread.
Map<String, List<List<String>>> _decodeCsvInBackground(List<int> bytes) {
final content = utf8.decode(bytes);
final lines = content.split('\n');
final List<List<String>> rows = [];
for (var line in lines) {
if (line.trim().isEmpty) continue;
if (rows.length >= 500) break; // Cap at 500 rows for mobile/desktop instant preview
final cols = line.split(',').map((e) => e.trim()).toList();
if (cols.length > 30) {
rows.add(cols.sublist(0, 30));
} else {
rows.add(cols);
}
}
return {'Sheet 1': rows};
}
/// Background isolate function to decode Excel bytes without blocking UI thread.
Map<String, List<List<String>>> _decodeExcelInBackground(List<int> bytes) {
final excel = Excel.decodeBytes(bytes);
final Map<String, List<List<String>>> parsedSheets = {};
for (final table in excel.tables.keys) {
final sheet = excel.tables[table];
if (sheet == null || sheet.rows.isEmpty) continue;
// 1st pass: find the actual last non-empty row and column in the sheet
int maxNonEmptyRow = -1;
int maxNonEmptyCol = -1;
final int rowLimit = math.min(sheet.rows.length, 500); // Cap at 500 rows
for (int r = 0; r < rowLimit; r++) {
final row = sheet.rows[r];
final int colLimit = math.min(row.length, 30); // Cap at 30 columns
for (int c = 0; c < colLimit; c++) {
final cell = row[c];
if (cell != null &&
cell.value != null &&
cell.value.toString().trim().isNotEmpty) {
if (r > maxNonEmptyRow) maxNonEmptyRow = r;
if (c > maxNonEmptyCol) maxNonEmptyCol = c;
}
}
}
if (maxNonEmptyRow == -1 || maxNonEmptyCol == -1) {
continue; // Skip completely empty sheets
}
// 2nd pass: extract ONLY up to maxNonEmptyRow and maxNonEmptyCol
final List<List<String>> sheetRows = [];
for (int r = 0; r <= maxNonEmptyRow; r++) {
final row = sheet.rows[r];
final List<String> rowCells = [];
for (int c = 0; c <= maxNonEmptyCol; c++) {
String valStr = '';
if (c < row.length) {
final cell = row[c];
if (cell != null && cell.value != null) {
final val = cell.value;
try {
if (val is TextCellValue) {
valStr = val.value.toString();
} else if (val is IntCellValue) {
valStr = val.value.toString();
} else if (val is DoubleCellValue) {
valStr = val.value.toString();
} else if (val is BoolCellValue) {
valStr = val.value ? 'TRUE' : 'FALSE';
} else {
valStr = val.toString();
}
} catch (_) {
valStr = val.toString();
}
}
}
rowCells.add(valStr);
}
sheetRows.add(rowCells);
}
parsedSheets[table] = sheetRows;
}
return parsedSheets;
}
class ExcelViewerWidget extends StatefulWidget {
final File? localFile;
final String? networkUrl;
@@ -116,17 +27,7 @@ class ExcelViewerWidget extends StatefulWidget {
class _ExcelViewerWidgetState extends State<ExcelViewerWidget> {
bool _isLoading = true;
String? _errorMessage;
// Workbook data
Map<String, List<List<String>>> _sheetData = {};
List<String> _sheetNames = [];
String? _activeSheetName;
// Search query
String _searchQuery = '';
// Scroll controllers for synchronized scrolling
final ScrollController _horizontalController = ScrollController();
Uint8List? _fileBytes;
@override
void initState() {
@@ -134,12 +35,6 @@ class _ExcelViewerWidgetState extends State<ExcelViewerWidget> {
_loadSpreadsheet();
}
@override
void dispose() {
_horizontalController.dispose();
super.dispose();
}
Future<void> _loadSpreadsheet() async {
setState(() {
_isLoading = true;
@@ -147,7 +42,7 @@ class _ExcelViewerWidgetState extends State<ExcelViewerWidget> {
});
try {
List<int> bytes;
Uint8List bytes;
if (widget.localFile != null) {
bytes = await widget.localFile!.readAsBytes();
} else if (widget.networkUrl != null && widget.networkUrl!.isNotEmpty) {
@@ -163,49 +58,27 @@ class _ExcelViewerWidgetState extends State<ExcelViewerWidget> {
if (response.data == null) {
throw Exception('Failed to download spreadsheet file.');
}
bytes = response.data!;
bytes = Uint8List.fromList(response.data!);
} else {
throw Exception('No file source provided.');
}
final lowerName = widget.fileName.toLowerCase();
Map<String, List<List<String>>> parsedSheets;
if (lowerName.endsWith('.csv')) {
// Run CSV parsing in background isolate
parsedSheets = await compute(_decodeCsvInBackground, bytes);
} else {
// Run Excel parsing in background isolate to avoid Windows UI freeze
parsedSheets = await compute(_decodeExcelInBackground, bytes);
}
if (mounted) {
setState(() {
_sheetData = parsedSheets;
_sheetNames = parsedSheets.keys.toList();
_activeSheetName = _sheetNames.isNotEmpty ? _sheetNames.first : null;
_fileBytes = bytes;
_isLoading = false;
});
}
} catch (e) {
if (mounted) {
setState(() {
_errorMessage = 'Could not read spreadsheet: $e';
_errorMessage = 'Could not load spreadsheet: $e';
_isLoading = false;
});
}
}
}
String _columnLetter(int index) {
String name = '';
int idx = index;
while (idx >= 0) {
name = String.fromCharCode((idx % 26) + 65) + name;
idx = (idx ~/ 26) - 1;
}
return name;
}
@override
Widget build(BuildContext context) {
if (_isLoading) {
@@ -224,7 +97,7 @@ class _ExcelViewerWidgetState extends State<ExcelViewerWidget> {
);
}
if (_errorMessage != null) {
if (_errorMessage != null || _fileBytes == null) {
return Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
@@ -243,7 +116,7 @@ class _ExcelViewerWidgetState extends State<ExcelViewerWidget> {
),
const SizedBox(height: 8),
Text(
_errorMessage!,
_errorMessage ?? 'Unable to display spreadsheet',
textAlign: TextAlign.center,
style: const TextStyle(
color: AppColors.textSecondary,
@@ -256,295 +129,9 @@ class _ExcelViewerWidgetState extends State<ExcelViewerWidget> {
);
}
final List<List<String>> activeRows =
_activeSheetName != null
? (_sheetData[_activeSheetName] ?? <List<String>>[])
: <List<String>>[];
final List<List<String>> filteredRows =
_searchQuery.isEmpty
? activeRows
: activeRows.where((row) {
return row.any(
(cell) =>
cell.toLowerCase().contains(_searchQuery.toLowerCase()),
);
}).toList();
// Determine max columns in this sheet (capped at 50 to prevent horizontal bloat)
int maxCols = 0;
for (final r in filteredRows) {
if (r.length > maxCols) maxCols = r.length;
}
if (maxCols == 0) maxCols = 1;
maxCols = math.min(maxCols, 50);
const double rowNumberWidth = 50.0;
const double cellWidth = 120.0;
final double totalTableWidth = rowNumberWidth + (maxCols * cellWidth);
return Column(
children: [
// Top search and statistics toolbar
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(color: Colors.grey.shade300, width: 1),
),
),
child: Row(
children: [
Icon(
Icons.table_chart_rounded,
size: 18,
color: Colors.green.shade700,
),
const SizedBox(width: 8),
Text(
'${filteredRows.length} Rows × $maxCols Columns',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.textSecondary,
),
),
const Spacer(),
// Search field
SizedBox(
width: widget.isMobile ? 140 : 220,
height: 34,
child: TextField(
decoration: InputDecoration(
hintText: 'Search table...',
hintStyle: const TextStyle(fontSize: 12),
prefixIcon: const Icon(Icons.search, size: 16),
contentPadding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 0,
),
isDense: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(6),
borderSide: BorderSide(color: Colors.grey.shade300),
),
),
style: const TextStyle(fontSize: 12),
onChanged: (val) {
setState(() => _searchQuery = val);
},
),
),
],
),
),
// Main table grid - using Scrollbar and virtualized ListView.builder for instant rendering
Expanded(
child: Container(
color: Colors.white,
child: Scrollbar(
controller: _horizontalController,
thumbVisibility: true,
child: SingleChildScrollView(
controller: _horizontalController,
scrollDirection: Axis.horizontal,
child: SizedBox(
width: totalTableWidth,
child: Column(
children: [
// Fixed Column Header Row (A, B, C...)
Container(
height: 34,
decoration: BoxDecoration(
color: Colors.grey.shade200,
border: Border(
bottom: BorderSide(
color: Colors.grey.shade400,
width: 1,
),
),
),
child: Row(
children: [
// Row number corner cell
Container(
width: rowNumberWidth,
alignment: Alignment.center,
color: Colors.grey.shade300,
child: const Text(
'#',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11,
color: AppColors.textSecondary,
),
),
),
for (int c = 0; c < maxCols; c++)
Container(
width: cellWidth,
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
right: BorderSide(
color: Colors.grey.shade300,
width: 1,
),
),
),
child: Text(
_columnLetter(c),
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
color: AppColors.textPrimary,
),
),
),
],
),
),
// Virtualized Data Rows - builds ONLY visible rows instantly
Expanded(
child: ListView.builder(
itemCount: filteredRows.length,
itemBuilder: (context, r) {
final rowCells = filteredRows[r];
return Container(
height: 32,
decoration: BoxDecoration(
color:
r % 2 == 0
? Colors.white
: Colors.grey.shade50,
border: Border(
bottom: BorderSide(
color: Colors.grey.shade200,
width: 1,
),
),
),
child: Row(
children: [
// Left Row Number (1, 2, 3...)
Container(
width: rowNumberWidth,
alignment: Alignment.center,
color: Colors.grey.shade200,
child: Text(
'${r + 1}',
style: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: AppColors.textSecondary,
),
),
),
// Cell Values
for (int c = 0; c < maxCols; c++)
Container(
width: cellWidth,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(
horizontal: 8,
),
decoration: BoxDecoration(
border: Border(
right: BorderSide(
color: Colors.grey.shade200,
width: 1,
),
),
),
child: Text(
c < rowCells.length ? rowCells[c] : '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 12,
color: AppColors.textPrimary,
),
),
),
],
),
);
},
),
),
],
),
),
),
),
),
),
// Bottom sheets TabBar (if multiple tabs exist)
if (_sheetNames.isNotEmpty)
Container(
height: 44,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border(
top: BorderSide(color: Colors.grey.shade300, width: 1),
),
),
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: _sheetNames.length,
separatorBuilder: (_, __) => const SizedBox(width: 8),
itemBuilder: (context, index) {
final name = _sheetNames[index];
final isSelected = name == _activeSheetName;
return Center(
child: InkWell(
onTap: () {
setState(() => _activeSheetName = name);
},
borderRadius: BorderRadius.circular(6),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 6,
),
decoration: BoxDecoration(
color:
isSelected
? Colors.green.shade700
: Colors.transparent,
borderRadius: BorderRadius.circular(6),
border: Border.all(
color:
isSelected
? Colors.green.shade700
: Colors.grey.shade300,
),
),
child: Text(
name,
style: TextStyle(
fontSize: 12,
fontWeight:
isSelected
? FontWeight.bold
: FontWeight.normal,
color:
isSelected
? Colors.white
: AppColors.textPrimary,
),
),
),
),
);
},
),
),
],
return Sheetifye.memory(
_fileBytes!,
readOnly: true,
);
}
}
@@ -51,16 +51,15 @@ class _StudentsScreenState extends ConsumerState<StudentsScreen> {
void initState() {
super.initState();
// Sync initial search text if it was set externally (e.g. from Dashboard)
final initialQuery = ref.read(studentQueryProvider).search;
if (initialQuery.isNotEmpty) {
_searchController.text = initialQuery;
}
_searchController.addListener(_onSearchChanged);
_searchFocusNode.addListener(_onSearchFocusChanged);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
// Sync initial search text if it was set externally (e.g. from Dashboard)
final initialQuery = ref.read(studentQueryProvider).search;
if (initialQuery.isNotEmpty) {
_searchController.text = initialQuery;
}
if (ref.read(activeTabProvider) == 'Students') {
_shortcutFocusNode.requestFocus();
}
+24 -160
View File
@@ -1,22 +1,6 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: a49d6cf99e8d8e7a8e93668d09ced0bbdb954d0b4fccc2f5f9241c6b87fad95c
url: "https://pub.dev"
source: hosted
version: "99.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "663efa951fb8a45e06f491223a604c93820598f20e6a99c25617a1576065e8b7"
url: "https://pub.dev"
source: hosted
version: "12.1.0"
ansicolor:
dependency: transitive
description:
@@ -129,14 +113,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.10"
cli_config:
dependency: transitive
description:
name: cli_config
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
url: "https://pub.dev"
source: hosted
version: "0.2.0"
cli_util:
dependency: transitive
description:
@@ -185,14 +161,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "956a3de0725ca232ad353565a8290d3357592bf4250f6f298a185e2d949c5d3d"
url: "https://pub.dev"
source: hosted
version: "1.15.1"
cross_file:
dependency: transitive
description:
@@ -450,10 +418,10 @@ packages:
dependency: "direct main"
description:
name: flutter_riverpod
sha256: "9255e1e3ad6e38906a1b4f8287678f95f378744c5b46b1985588543f3f19046e"
sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1"
url: "https://pub.dev"
source: hosted
version: "3.3.2"
version: "2.6.1"
flutter_secure_storage:
dependency: "direct main"
description:
@@ -520,14 +488,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client:
freezed_annotation:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
name: freezed_annotation
sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2
url: "https://pub.dev"
source: hosted
version: "4.0.0"
version: "2.4.4"
get_it:
dependency: transitive
description:
@@ -536,14 +504,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "9.2.1"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
google_fonts:
dependency: "direct main"
description:
@@ -584,14 +544,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.6.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.2"
http_parser:
dependency: transitive
description:
@@ -680,14 +632,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.20.3"
io:
dependency: transitive
description:
name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.5"
jni:
dependency: transitive
description:
@@ -816,14 +760,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.17.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
objective_c:
dependency: transitive
description:
@@ -992,14 +928,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pool:
dependency: transitive
description:
name: pool
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
url: "https://pub.dev"
source: hosted
version: "1.5.2"
printing:
dependency: "direct main"
description:
@@ -1052,10 +980,18 @@ packages:
dependency: transitive
description:
name: riverpod
sha256: "17100416c51db7810c71a7bb2c34d1f881faa0074fd452afb0c4db6f8f126c76"
sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959"
url: "https://pub.dev"
source: hosted
version: "3.3.2"
version: "2.6.1"
riverpod_annotation:
dependency: transitive
description:
name: riverpod_annotation
sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8
url: "https://pub.dev"
source: hosted
version: "2.6.1"
screen_retriever:
dependency: transitive
description:
@@ -1152,35 +1088,19 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shelf:
dependency: transitive
sheetifye:
dependency: "direct main"
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
name: sheetifye
sha256: "096537cc78c896b51c1427ab31296ebe59539b50b5f0fcd2db2a65be1d9e00d9"
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
version: "1.1.0"
shimmer:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
name: shimmer
sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
@@ -1205,22 +1125,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.1"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
url: "https://pub.dev"
source: hosted
version: "0.10.13"
source_span:
dependency: transitive
description:
@@ -1341,14 +1245,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test:
dependency: transitive
description:
name: test
sha256: "8d9ceddbab833f180fbefed08afa76d7c03513dfdba87ffcec2718b02bbcbf20"
url: "https://pub.dev"
source: hosted
version: "1.31.0"
test_api:
dependency: transitive
description:
@@ -1357,14 +1253,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.11"
test_core:
dependency: transitive
description:
name: test_core
sha256: "1991d4cfe85d5043241acac92962c3977c8d2f2add1ee73130c7b286417d1d34"
url: "https://pub.dev"
source: hosted
version: "0.6.17"
timezone:
dependency: transitive
description:
@@ -1493,14 +1381,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "15.2.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
web:
dependency: transitive
description:
@@ -1517,22 +1397,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
win32:
dependency: transitive
description:
+7 -2
View File
@@ -34,7 +34,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
flutter_riverpod: ^3.3.1
flutter_riverpod: ^2.6.1
dio: ^5.9.2
flutter_secure_storage: ^10.1.0
google_fonts: ^8.1.0
@@ -58,7 +58,8 @@ dependencies:
wolt_modal_sheet: ^0.11.0
printing: ^5.14.3
pdf: ^3.12.0
intl: ^0.20.3
intl: ^0.19.0
sheetifye: ^1.1.0
flutter_local_notifications: ^17.2.2
workmanager: ^0.9.0+3
desktop_drop: ^0.7.1
@@ -79,6 +80,10 @@ dev_dependencies:
flutter_native_splash: ^2.4.4
cider: ^0.2.10
dependency_overrides:
google_fonts: ^8.1.0
intl: ^0.20.3
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec