updated book folder structure

This commit is contained in:
2025-04-07 20:59:41 +02:00
parent b822fe1ca3
commit ba75cb70a2
+82 -76
View File
@@ -100,25 +100,36 @@ Color _getColorFromName(String colorName) {
Map<String, List<File>> groupedFiles = {}; Map<String, List<File>> groupedFiles = {};
Map<String, DateTime> folderDates = {}; Map<String, DateTime> folderDates = {};
Map<String, int> folderScores = {}; Map<String, int> folderScores = {};
Map<String, bool> folderTypes = {}; // ✅ Map<String, bool> folderTypes = {};
for (var folder in folders) { for (var folder in folders) {
String folderName = folder.path.split('/').last; String folderName = folder.path.split('/').last;
DateTime folderDate = folder.statSync().modified; DateTime fallbackDate = folder.statSync().changed; // fallback
// ✅ Read isTournament flag // Read metadata
bool isTournament = false;
final metadataFile = File('${folder.path}/metadata.json'); final metadataFile = File('${folder.path}/metadata.json');
bool isTournament = false;
DateTime? createdAt;
if (await metadataFile.exists()) { if (await metadataFile.exists()) {
try { try {
final metadata = jsonDecode(await metadataFile.readAsString()); final metadata = jsonDecode(await metadataFile.readAsString());
isTournament = metadata['isTournament'] == true; isTournament = metadata['isTournament'] == true;
if (metadata['createdAt'] != null) {
createdAt = DateTime.tryParse(metadata['createdAt']);
}
} catch (e) { } catch (e) {
debugPrint("Error reading metadata for $folderName: $e"); debugPrint("Error reading metadata for $folderName: $e");
} }
} }
// Use createdAt if available, fallback otherwise
folderDates[folderName] = createdAt ?? fallbackDate;
folderTypes[folderName] = isTournament; folderTypes[folderName] = isTournament;
// List target files
List<File> targetFiles = Directory(folder.path) List<File> targetFiles = Directory(folder.path)
.listSync() .listSync()
.whereType<File>() .whereType<File>()
@@ -131,36 +142,30 @@ Color _getColorFromName(String colorName) {
for (var file in targetFiles) { for (var file in targetFiles) {
final jsonString = await file.readAsString(); final jsonString = await file.readAsString();
final data = jsonDecode(jsonString); final data = jsonDecode(jsonString);
final score = _getScoreFromJson(data); totalScore += _getScoreFromJson(data);
totalScore += score;
} }
groupedFiles[folderName] = targetFiles; groupedFiles[folderName] = targetFiles;
folderDates[folderName] = folderDate;
folderScores[folderName] = totalScore; folderScores[folderName] = totalScore;
} }
// Sort folders by stored or fallback created date (DESC)
final sortedFolderNames = folderDates.keys.toList() final sortedFolderNames = folderDates.keys.toList()
..sort((a, b) => folderDates[b]!.compareTo(folderDates[a]!)); ..sort((a, b) => folderDates[b]!.compareTo(folderDates[a]!));
final sortedGroupedFiles = {
for (var folderName in sortedFolderNames) folderName: groupedFiles[folderName]!
};
final sortedFolderScores = {
for (var folderName in sortedFolderNames) folderName: folderScores[folderName]!
};
final sortedFolderDates = {
for (var folderName in sortedFolderNames) folderName: folderDates[folderName]!
};
final sortedFolderTypes = {
for (var folderName in sortedFolderNames) folderName: folderTypes[folderName]!
};
setState(() { setState(() {
_groupedFiles = sortedGroupedFiles; _groupedFiles = {
_folderCreationDates = sortedFolderDates; for (var name in sortedFolderNames) name: groupedFiles[name]!
_folderScores = sortedFolderScores; };
_folderTypes = sortedFolderTypes; // ✅ FIXED _folderCreationDates = {
for (var name in sortedFolderNames) name: folderDates[name]!
};
_folderScores = {
for (var name in sortedFolderNames) name: folderScores[name]!
};
_folderTypes = {
for (var name in sortedFolderNames) name: folderTypes[name]!
};
}); });
} catch (e) { } catch (e) {
debugPrint("Error loading target data files: $e"); debugPrint("Error loading target data files: $e");
@@ -168,6 +173,7 @@ Color _getColorFromName(String colorName) {
} }
// Function to safely get the score from the JSON data // Function to safely get the score from the JSON data
int _getScoreFromJson(Map<String, dynamic> data) { int _getScoreFromJson(Map<String, dynamic> data) {
if (data.containsKey('totalScore') && data['totalScore'] is int) { if (data.containsKey('totalScore') && data['totalScore'] is int) {
@@ -250,22 +256,30 @@ Color _getColorFromName(String colorName) {
), ),
), ),
); );
}
List<String> _filteredFolderNames() {
final List<String> folders = _groupedFiles.keys.toList();
if (_folderFilter != 'all') {
final isTournament = _folderFilter == 'tournament';
folders.retainWhere((folderName) => _folderTypes[folderName] == isTournament);
}
// 🔽 Sort using `createdAt` from _folderCreationDates (which is now based on metadata.json)
folders.sort((a, b) {
final dateA = _folderCreationDates[a];
final dateB = _folderCreationDates[b];
if (dateA == null || dateB == null) return 0;
return dateB.compareTo(dateA); // Newest first
});
return folders;
} }
List<String> _filteredFolderNames() {
if (_folderFilter == 'all') return _groupedFiles.keys.toList();
final isTournamentFilter = _folderFilter == 'tournament'; Future<void> _renameFolder(String oldFolderName) async {
return _groupedFiles.keys
.where((folderName) => _folderTypes[folderName] == isTournamentFilter)
.toList();
}
// Rename folder
Future<void> _renameFolder(String oldFolderName) async {
final newNameController = TextEditingController(); final newNameController = TextEditingController();
bool isTournament = _folderTypes[oldFolderName] == true; bool isTournament = _folderTypes[oldFolderName] == true;
final result = await showDialog<Map<String, dynamic>>( final result = await showDialog<Map<String, dynamic>>(
@@ -291,7 +305,6 @@ List<String> _filteredFolderNames() {
), ),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
TextField( TextField(
controller: newNameController, controller: newNameController,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@@ -301,8 +314,7 @@ List<String> _filteredFolderNames() {
fillColor: Colors.grey[800], fillColor: Colors.grey[800],
hintText: 'Enter new folder name', hintText: 'Enter new folder name',
hintStyle: const TextStyle(color: Colors.white54), hintStyle: const TextStyle(color: Colors.white54),
contentPadding: contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none, borderSide: BorderSide.none,
@@ -319,7 +331,6 @@ List<String> _filteredFolderNames() {
}, },
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
setState(() { setState(() {
@@ -329,28 +340,19 @@ List<String> _filteredFolderNames() {
child: Container( child: Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isTournament color: isTournament ? _bulletColor.withOpacity(0.2) : Colors.grey[850],
? _bulletColor.withOpacity(0.2)
: Colors.grey[850],
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all( border: Border.all(
color: isTournament color: isTournament ? _bulletColor : Colors.grey[700]!,
? _bulletColor
: Colors.grey[700]!,
width: 1.5, width: 1.5,
), ),
), ),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
horizontal: 16, vertical: 14),
child: Center( child: Center(
child: Text( child: Text(
isTournament isTournament ? 'Tournament Mode 🏆' : 'Mark as Tournament 🏆',
? 'Tournament Mode 🏆'
: 'Mark as Tournament 🏆',
style: TextStyle( style: TextStyle(
color: isTournament color: isTournament ? _bulletColor : Colors.white70,
? _bulletColor
: Colors.white70,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontSize: 16, fontSize: 16,
), ),
@@ -359,7 +361,6 @@ List<String> _filteredFolderNames() {
), ),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Row( Row(
children: [ children: [
Expanded( Expanded(
@@ -368,8 +369,7 @@ List<String> _filteredFolderNames() {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[800], backgroundColor: Colors.grey[800],
foregroundColor: Colors.white, foregroundColor: Colors.white,
padding: padding: const EdgeInsets.symmetric(vertical: 12),
const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@@ -387,8 +387,7 @@ List<String> _filteredFolderNames() {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: _bulletColor, backgroundColor: _bulletColor,
foregroundColor: Colors.white, foregroundColor: Colors.white,
padding: padding: const EdgeInsets.symmetric(vertical: 12),
const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@@ -407,26 +406,20 @@ List<String> _filteredFolderNames() {
}, },
); );
// ✅ Handle result (rename + update tag) // ✅ Handle result (rename + tag update)
if (result != null) { if (result != null) {
final newName = result['name']; final newName = result['name'];
final isTournament = result['isTournament'] ?? false; final isTournament = result['isTournament'] ?? false;
final directory = await getApplicationDocumentsDirectory(); final directory = await getApplicationDocumentsDirectory();
final oldFolderPath = final oldFolderPath = Directory('${directory.path}/saved_images/$oldFolderName');
Directory('${directory.path}/saved_images/$oldFolderName'); final targetFolderName = (newName != null && newName.isNotEmpty) ? newName : oldFolderName;
final newFolderPath = Directory('${directory.path}/saved_images/$targetFolderName');
final targetFolderName =
(newName != null && newName.isNotEmpty) ? newName : oldFolderName;
final newFolderPath =
Directory('${directory.path}/saved_images/$targetFolderName');
if (targetFolderName != oldFolderName) { if (targetFolderName != oldFolderName) {
if (await newFolderPath.exists()) { if (await newFolderPath.exists()) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(content: Text('A folder named "$targetFolderName" already exists.')),
content: Text('A folder named "$targetFolderName" already exists.')),
); );
return; return;
} else { } else {
@@ -434,20 +427,33 @@ List<String> _filteredFolderNames() {
} }
} }
// ✅ Preserve existing createdAt value or set it if missing
final metadataFile = File('${newFolderPath.path}/metadata.json'); final metadataFile = File('${newFolderPath.path}/metadata.json');
if (isTournament) { String? createdAt;
await metadataFile.writeAsString(jsonEncode({'isTournament': true}));
} else {
if (await metadataFile.exists()) { if (await metadataFile.exists()) {
await metadataFile.delete(); try {
} final existing = jsonDecode(await metadataFile.readAsString());
createdAt = existing['createdAt'];
} catch (_) {}
} }
_loadTargetDataFiles(); // refresh UI createdAt ??= DateTime.now().toIso8601String(); // fallback if not found
final updatedMetadata = {
'isTournament': isTournament,
'createdAt': createdAt,
};
await metadataFile.writeAsString(jsonEncode(updatedMetadata));
_loadTargetDataFiles(); // Refresh UI
} }
} }
// Delete a folder // Delete a folder
Future<void> _deleteFolder(String folderName) async { Future<void> _deleteFolder(String folderName) async {
bool? confirmDeletion = await _showConfirmationDialog( bool? confirmDeletion = await _showConfirmationDialog(