5 changed files with 240 additions and 5 deletions
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
// template_parser_controller.dart |
||||
|
||||
import 'package:file_picker/file_picker.dart'; |
||||
import 'package:win_text_editor/framework/controllers/logger.dart'; |
||||
import 'package:win_text_editor/shared/base/base_content_controller.dart'; |
||||
|
||||
class TemplateParserController extends BaseContentController { |
||||
String _filePath = ''; |
||||
List<TemplateNode> _treeNodes = []; |
||||
List<TemplateItem> _templateItems = []; |
||||
|
||||
// Getters |
||||
String get filePath => _filePath; |
||||
List<TemplateNode> get treeNodes => _treeNodes; |
||||
List<TemplateItem> get templateItems => _templateItems; |
||||
|
||||
Future<void> pickFile() async { |
||||
final result = await FilePicker.platform.pickFiles(); |
||||
if (result != null) { |
||||
_filePath = result.files.single.path!; |
||||
_loadTemplateData(); // Simulate loading data |
||||
notifyListeners(); |
||||
} |
||||
} |
||||
|
||||
void setFilePath(String path) { |
||||
_filePath = path; |
||||
_loadTemplateData(); // Simulate loading data |
||||
notifyListeners(); |
||||
} |
||||
|
||||
void selectTreeNode(TemplateNode node) { |
||||
// Simulate loading items when a tree node is selected |
||||
_templateItems = List.generate( |
||||
10, |
||||
(index) => TemplateItem(id: index + 1, content: 'Content for ${node.name} item ${index + 1}'), |
||||
); |
||||
notifyListeners(); |
||||
} |
||||
|
||||
void _loadTemplateData() { |
||||
// Simulate loading tree data |
||||
_treeNodes = [ |
||||
TemplateNode('Section 1', [ |
||||
TemplateNode('Subsection 1.1', []), |
||||
TemplateNode('Subsection 1.2', []), |
||||
]), |
||||
TemplateNode('Section 2', [ |
||||
TemplateNode('Subsection 2.1', []), |
||||
TemplateNode('Subsection 2.2', []), |
||||
]), |
||||
]; |
||||
|
||||
// Simulate loading initial items |
||||
_templateItems = List.generate( |
||||
15, |
||||
(index) => TemplateItem(id: index + 1, content: 'Initial template content ${index + 1}'), |
||||
); |
||||
} |
||||
|
||||
@override |
||||
void onOpenFile(String filePath) { |
||||
Logger().info('File selected: $filePath'); |
||||
setFilePath(filePath); |
||||
} |
||||
|
||||
@override |
||||
void onOpenFolder(String folderPath) { |
||||
// TODO: implement onOpenFolder |
||||
} |
||||
} |
||||
|
||||
class TemplateNode { |
||||
final String name; |
||||
final List<TemplateNode> children; |
||||
|
||||
TemplateNode(this.name, this.children); |
||||
} |
||||
|
||||
class TemplateItem { |
||||
final int id; |
||||
final String content; |
||||
|
||||
TemplateItem({required this.id, required this.content}); |
||||
} |
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
// template_parser_view.dart |
||||
import 'package:flutter/material.dart'; |
||||
import 'package:provider/provider.dart'; |
||||
import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; |
||||
import 'package:win_text_editor/modules/template_parser/controllers/template_parser_controller.dart'; |
||||
|
||||
class TemplateParserView extends StatefulWidget { |
||||
final String tabId; |
||||
const TemplateParserView({super.key, required this.tabId}); |
||||
|
||||
@override |
||||
State<TemplateParserView> createState() => _TemplateParserViewState(); |
||||
} |
||||
|
||||
class _TemplateParserViewState extends State<TemplateParserView> { |
||||
late final TemplateParserController _controller; |
||||
|
||||
get tabManager => Provider.of<TabItemsController>(context, listen: false); |
||||
|
||||
@override |
||||
void initState() { |
||||
super.initState(); |
||||
_controller = tabManager.getController(widget.tabId) ?? TemplateParserController(); |
||||
} |
||||
|
||||
@override |
||||
void dispose() { |
||||
_controller.dispose(); |
||||
super.dispose(); |
||||
} |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return ChangeNotifierProvider.value( |
||||
value: _controller, |
||||
child: Padding( |
||||
padding: const EdgeInsets.all(8.0), |
||||
child: Column( |
||||
children: [ |
||||
_buildFilePathInput(), |
||||
const SizedBox(height: 8), |
||||
Expanded(child: _buildMainContent()), |
||||
], |
||||
), |
||||
), |
||||
); |
||||
} |
||||
|
||||
Widget _buildFilePathInput() { |
||||
return Consumer<TemplateParserController>( |
||||
builder: (context, controller, _) { |
||||
return TextField( |
||||
decoration: InputDecoration( |
||||
labelText: 'Template File', |
||||
hintText: 'Select a template file', |
||||
suffixIcon: IconButton( |
||||
icon: const Icon(Icons.folder_open), |
||||
onPressed: controller.pickFile, |
||||
), |
||||
border: const OutlineInputBorder(), |
||||
), |
||||
controller: TextEditingController(text: controller.filePath), |
||||
readOnly: true, |
||||
); |
||||
}, |
||||
); |
||||
} |
||||
|
||||
Widget _buildMainContent() { |
||||
return Consumer<TemplateParserController>( |
||||
builder: (context, controller, _) { |
||||
return Row( |
||||
children: [ |
||||
// Tree view (30% width) |
||||
SizedBox( |
||||
width: MediaQuery.of(context).size.width * 0.3, |
||||
child: Card(child: _buildTreeView(controller.treeNodes)), |
||||
), |
||||
const SizedBox(width: 8), |
||||
// Grid view (70% width) |
||||
Expanded(child: Card(child: _buildGridView(controller.templateItems))), |
||||
], |
||||
); |
||||
}, |
||||
); |
||||
} |
||||
|
||||
Widget _buildTreeView(List<TemplateNode> nodes) { |
||||
return ListView.builder( |
||||
itemCount: nodes.length, |
||||
itemBuilder: (context, index) { |
||||
return _buildTreeNode(nodes[index]); |
||||
}, |
||||
); |
||||
} |
||||
|
||||
Widget _buildTreeNode(TemplateNode node) { |
||||
return ExpansionTile( |
||||
title: Text(node.name), |
||||
children: node.children.map((child) => _buildTreeNode(child)).toList(), |
||||
onExpansionChanged: (expanded) { |
||||
if (expanded) { |
||||
Provider.of<TemplateParserController>(context, listen: false).selectTreeNode(node); |
||||
} |
||||
}, |
||||
); |
||||
} |
||||
|
||||
Widget _buildGridView(List<TemplateItem> items) { |
||||
return GridView.builder( |
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( |
||||
crossAxisCount: 2, |
||||
childAspectRatio: 5, |
||||
), |
||||
itemCount: items.length, |
||||
itemBuilder: (context, index) { |
||||
final item = items[index]; |
||||
return Card( |
||||
child: Padding( |
||||
padding: const EdgeInsets.all(8.0), |
||||
child: Column( |
||||
crossAxisAlignment: CrossAxisAlignment.start, |
||||
children: [Text('ID: ${item.id}'), Text('Content: ${item.content}')], |
||||
), |
||||
), |
||||
); |
||||
}, |
||||
); |
||||
} |
||||
} |
Loading…
Reference in new issue