Skip to content

Commit 14723d6

Browse files
authored
Update home_screen.dart [build]
1 parent b49b3f9 commit 14723d6

File tree

1 file changed

+125
-166
lines changed

1 file changed

+125
-166
lines changed

lib/ui/screens/home_screen.dart

Lines changed: 125 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,151 @@
1-
import 'dart:io';
1+
import 'dart:convert';
22
import 'package:flutter/material.dart';
3-
import '../../core/storage_service.dart';
4-
import 'document_viewer_screen.dart';
5-
import 'settings_screen.dart'; // Importuj svoj novi settings fajl
3+
import 'package:fleather/fleather.dart';
4+
import 'package:parchment/parchment.dart';
5+
import 'package:hive/hive.dart';
6+
import 'package:share_plus/share_plus.dart';
67

7-
class HomeScreen extends StatefulWidget {
8-
const HomeScreen({super.key});
8+
class DocumentViewerScreen extends StatefulWidget {
9+
final String? fileName;
10+
const DocumentViewerScreen({super.key, this.fileName});
911

1012
@override
11-
State<HomeScreen> createState() => _HomeScreenState();
13+
State<DocumentViewerScreen> createState() => _DocumentViewerScreenState();
1214
}
1315

14-
class _HomeScreenState extends State<HomeScreen> {
15-
// Funkcija za osvežavanje liste nakon kreiranja ili brisanja
16-
void _refreshList() {
17-
setState(() {});
16+
class _DocumentViewerScreenState extends State<DocumentViewerScreen> {
17+
FleatherController? _controller;
18+
late Box _box;
19+
final String _defaultDocName = "new_note";
20+
final FocusNode _focusNode = FocusNode();
21+
22+
@override
23+
void initState() {
24+
super.initState();
25+
_box = Hive.box('documents_box');
26+
_loadDocument();
27+
_controller!.addListener(_autoSave);
1828
}
1929

20-
// Dijalog za kreiranje novog dokumenta
21-
Future<void> _showCreateDialog() async {
22-
String newFileName = "";
23-
return showDialog(
24-
context: context,
25-
builder: (context) {
26-
return AlertDialog(
27-
title: const Text("New Document", style: TextStyle(fontWeight: FontWeight.w300)),
28-
content: TextField(
29-
autofocus: true,
30-
onChanged: (value) => newFileName = value,
31-
decoration: const InputDecoration(
32-
hintText: "Enter file name",
33-
border: UnderlineInputBorder(),
34-
),
35-
),
36-
actions: [
37-
TextButton(
38-
onPressed: () => Navigator.pop(context),
39-
child: const Text("Cancel"),
40-
),
41-
TextButton(
42-
onPressed: () {
43-
if (newFileName.isNotEmpty) {
44-
Navigator.pop(context);
45-
Navigator.push(
46-
context,
47-
MaterialPageRoute(
48-
builder: (_) => DocumentViewerScreen(
49-
fileName: newFileName.endsWith('.txt')
50-
? newFileName
51-
: '$newFileName.txt',
52-
),
53-
),
54-
).then((_) => _refreshList());
55-
}
56-
},
57-
child: const Text("Create"),
58-
),
59-
],
60-
);
61-
},
62-
);
30+
void _loadDocument() {
31+
final String key = widget.fileName ?? _defaultDocName;
32+
final String? savedData = _box.get(key);
33+
34+
if (savedData != null) {
35+
try {
36+
final doc = ParchmentDocument.fromJson(jsonDecode(savedData));
37+
_controller = FleatherController(document: doc);
38+
} catch (e) {
39+
_controller = FleatherController();
40+
}
41+
} else {
42+
_controller = FleatherController();
43+
}
44+
}
45+
46+
void _autoSave() {
47+
final String key = widget.fileName ?? _defaultDocName;
48+
final deltaData = jsonEncode(_controller!.document.toDelta());
49+
_box.put(key, deltaData);
50+
}
51+
52+
// Funkcija koja pretvara bogat tekst u običan string za deljenje
53+
void _shareDocument() {
54+
final String plainText = _controller!.document.toPlainText();
55+
final String title = widget.fileName ?? 'Untitled Note';
56+
57+
if (plainText.trim().isNotEmpty) {
58+
Share.share(plainText, subject: title);
59+
} else {
60+
ScaffoldMessenger.of(context).showSnackBar(
61+
const SnackBar(content: Text("Cannot share an empty note")),
62+
);
63+
}
6364
}
6465

6566
@override
6667
Widget build(BuildContext context) {
68+
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
69+
final bool isKeyboardVisible = bottomInset > 0;
70+
final safeBottomPadding = MediaQuery.of(context).padding.bottom;
71+
6772
return Scaffold(
73+
resizeToAvoidBottomInset: false,
6874
appBar: AppBar(
69-
title: const Text("f.Sentence", style: TextStyle(fontWeight: FontWeight.w300)),
70-
centerTitle: true,
71-
// Hamburger ikona
72-
leading: Builder(
73-
builder: (context) => IconButton(
74-
icon: const Icon(Icons.menu),
75-
onPressed: () => Scaffold.of(context).openDrawer(),
76-
),
75+
title: Text(
76+
widget.fileName ?? 'f.Sentence',
77+
style: const TextStyle(fontWeight: FontWeight.w300),
7778
),
79+
actions: [
80+
IconButton(
81+
icon: const Icon(Icons.share_outlined),
82+
tooltip: 'Share as text',
83+
onPressed: _shareDocument,
84+
),
85+
],
7886
),
79-
// Meni sa leve strane
80-
drawer: Drawer(
81-
child: Column(
82-
children: [
83-
DrawerHeader(
84-
decoration: BoxDecoration(
85-
color: Theme.of(context).colorScheme.surfaceContainerHighest.withOpacity(0.5),
86-
),
87-
child: const Center(
88-
child: Text(
89-
"f.Sentence",
90-
style: TextStyle(fontSize: 28, fontWeight: FontWeight.w200),
87+
body: Stack(
88+
children: [
89+
Positioned.fill(
90+
child: Padding(
91+
padding: const EdgeInsets.symmetric(horizontal: 16),
92+
child: GestureDetector(
93+
onTap: () => _focusNode.requestFocus(),
94+
child: FleatherEditor(
95+
controller: _controller!,
96+
focusNode: _focusNode,
97+
readOnly: false,
98+
enableInteractiveSelection: true,
99+
padding: EdgeInsets.only(
100+
top: 16,
101+
bottom: isKeyboardVisible ? bottomInset + 80 : 100,
102+
),
91103
),
92104
),
93105
),
94-
ListTile(
95-
leading: const Icon(Icons.settings_outlined),
96-
title: const Text("Settings"),
97-
onTap: () {
98-
Navigator.pop(context); // Zatvori meni
99-
Navigator.push(
100-
context,
101-
MaterialPageRoute(builder: (_) => const SettingsScreen()),
102-
).then((_) => _refreshList());
103-
},
104-
),
105-
const Spacer(),
106-
const Padding(
107-
padding: EdgeInsets.all(16.0),
108-
child: Text(
109-
"v1.0.1",
110-
style: TextStyle(color: Colors.grey, fontSize: 12),
111-
),
112-
),
113-
],
114-
),
115-
),
116-
body: FutureBuilder<List<File>>(
117-
future: StorageService.getLocalFiles(),
118-
builder: (context, snapshot) {
119-
if (snapshot.connectionState == ConnectionState.waiting) {
120-
return const Center(child: CircularProgressIndicator());
121-
}
122-
123-
if (!snapshot.hasData || snapshot.data!.isEmpty) {
124-
return Center(
125-
child: Column(
126-
mainAxisAlignment: MainAxisAlignment.center,
127-
children: [
128-
Icon(Icons.note_add_outlined, size: 64, color: Colors.grey.withOpacity(0.5)),
129-
const SizedBox(height: 16),
130-
const Text("No documents yet.", style: TextStyle(color: Colors.grey)),
131-
],
132-
),
133-
);
134-
}
135-
136-
final files = snapshot.data!;
137-
138-
return ListView.builder(
139-
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
140-
itemCount: files.length,
141-
itemBuilder: (context, index) {
142-
final file = files[index];
143-
final fileName = file.path.split('/').last;
106+
),
144107

145-
return Card(
146-
elevation: 0,
147-
shape: RoundedRectangleBorder(
148-
borderRadius: BorderRadius.circular(16),
149-
side: BorderSide(
150-
color: Theme.of(context).colorScheme.outlineVariant,
151-
width: 1,
152-
),
153-
),
154-
margin: const EdgeInsets.only(bottom: 12),
155-
child: ListTile(
156-
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
157-
leading: CircleAvatar(
158-
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
159-
child: Icon(Icons.article_outlined,
160-
color: Theme.of(context).colorScheme.onPrimaryContainer),
161-
),
162-
title: Text(
163-
fileName,
164-
style: const TextStyle(fontWeight: FontWeight.w400),
165-
),
166-
subtitle: Text(
167-
"Last modified: ${file.lastModifiedSync().day}.${file.lastModifiedSync().month}.${file.lastModifiedSync().year}",
168-
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
108+
Positioned(
109+
bottom: isKeyboardVisible
110+
? bottomInset + 16
111+
: safeBottomPadding + 16,
112+
left: 16,
113+
right: 16,
114+
child: Material(
115+
elevation: 6,
116+
shadowColor: Colors.black38,
117+
borderRadius: BorderRadius.circular(30),
118+
color: Theme.of(context).colorScheme.surfaceContainerHighest,
119+
clipBehavior: Clip.antiAlias,
120+
child: Container(
121+
height: 56,
122+
padding: const EdgeInsets.symmetric(horizontal: 12),
123+
child: Theme(
124+
data: Theme.of(context).copyWith(
125+
dividerColor: Colors.transparent,
169126
),
170-
onTap: () {
171-
Navigator.push(
172-
context,
173-
MaterialPageRoute(
174-
builder: (_) => DocumentViewerScreen(fileName: fileName),
127+
child: Center(
128+
child: SingleChildScrollView(
129+
scrollDirection: Axis.horizontal,
130+
child: FleatherToolbar.basic(
131+
controller: _controller!,
175132
),
176-
).then((_) => _refreshList());
177-
},
133+
),
134+
),
178135
),
179-
);
180-
},
181-
);
182-
},
183-
),
184-
floatingActionButton: FloatingActionButton.extended(
185-
onPressed: _showCreateDialog,
186-
label: const Text("New Note"),
187-
icon: const Icon(Icons.add),
188-
elevation: 2,
136+
),
137+
),
138+
),
139+
],
189140
),
190141
);
191142
}
192-
}
143+
144+
@override
145+
void dispose() {
146+
_controller?.removeListener(_autoSave);
147+
_controller?.dispose();
148+
_focusNode.dispose();
149+
super.dispose();
150+
}
151+
}

0 commit comments

Comments
 (0)