squash pdf export + storage permissions
This commit is contained in:
43
lib/app.dart
43
lib/app.dart
@ -20,9 +20,7 @@ class _AppState extends State<App> {
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider(
|
||||
create: (ctx) {
|
||||
final notifier = FileChangeNotifier();
|
||||
notifier.loadAllNotes();
|
||||
return notifier;
|
||||
return FileChangeNotifier()..loadAllNotes();
|
||||
},
|
||||
child: Scaffold(
|
||||
floatingActionButton: _fab(),
|
||||
@ -48,27 +46,28 @@ class _AppState extends State<App> {
|
||||
switch (activePage) {
|
||||
case View.all:
|
||||
case View.folders:
|
||||
return FloatingActionButton(
|
||||
onPressed: () async {
|
||||
final now = DateTime.now();
|
||||
final name =
|
||||
'note-${now.year}_${now.month}_${now.day}-${now.hour}_${now.minute}';
|
||||
final filename = '$name.dbnote';
|
||||
return Consumer<FileChangeNotifier>(
|
||||
builder: (ctx, notifier, child) => FloatingActionButton(
|
||||
onPressed: () async {
|
||||
final now = DateTime.now();
|
||||
final name =
|
||||
'note-${now.year}_${now.month}_${now.day}-${now.hour}_${now.minute}_${now.second}';
|
||||
final filename = '$name.dbnote';
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (ctx) => DrawingPage(
|
||||
filePath: filename,
|
||||
name: name,
|
||||
Navigator.push(
|
||||
ctx,
|
||||
MaterialPageRoute(
|
||||
builder: (ctx) => DrawingPage(
|
||||
filePath: filename,
|
||||
name: name,
|
||||
),
|
||||
),
|
||||
),
|
||||
).then((value) =>
|
||||
Provider.of<FileChangeNotifier>(context, listen: false)
|
||||
.loadAllNotes());
|
||||
},
|
||||
backgroundColor: const Color(0xff3f3f3f),
|
||||
child: const Icon(Icons.edit_calendar_outlined, color: Colors.orange),
|
||||
).then((v) => notifier.loadAllNotes());
|
||||
},
|
||||
backgroundColor: const Color(0xff3f3f3f),
|
||||
child:
|
||||
const Icon(Icons.edit_calendar_outlined, color: Colors.orange),
|
||||
),
|
||||
);
|
||||
default:
|
||||
return Container();
|
||||
|
@ -5,6 +5,7 @@ import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../export/export_pdf.dart';
|
||||
import '../savesystem/note_file.dart';
|
||||
import '../widgets/icon_material_button.dart';
|
||||
import '../widgets/tool_bar.dart';
|
||||
@ -72,6 +73,7 @@ class _DrawingPageState extends State<DrawingPage> {
|
||||
color: const Color.fromRGBO(255, 255, 255, .85),
|
||||
onPressed: () {
|
||||
// todo implement
|
||||
exportPDF(controller.strokes, '${widget.name}.pdf');
|
||||
},
|
||||
),
|
||||
IconMaterialButton(
|
||||
|
@ -128,6 +128,7 @@ class PaintController extends ChangeNotifier {
|
||||
|
||||
Point p = Point(offset, newWidth);
|
||||
strokes.last.addPoint(p);
|
||||
// todo do a batch commit per stroke
|
||||
file.addPoint(strokes.last.id, p);
|
||||
break;
|
||||
case Pen.selector:
|
||||
|
@ -12,6 +12,10 @@ class FileChangeNotifier extends ChangeNotifier {
|
||||
|
||||
Future<List<NoteTileData>> loadAllNotes() async {
|
||||
final path = await getSavePath();
|
||||
if (!(await path.exists())) {
|
||||
await path.create(recursive: true);
|
||||
}
|
||||
|
||||
final dta = await path
|
||||
.list()
|
||||
.where((fsentity) => fsentity.path.endsWith('.dbnote'))
|
||||
|
58
lib/export/export_pdf.dart
Normal file
58
lib/export/export_pdf.dart
Normal file
@ -0,0 +1,58 @@
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:pdf/pdf.dart';
|
||||
import 'package:pdf/widgets.dart' as pw;
|
||||
|
||||
import '../canvas/document_types.dart';
|
||||
import '../savesystem/path.dart';
|
||||
|
||||
const _a4width = 210 * PdfPageFormat.mm;
|
||||
const _a4height = 297 * PdfPageFormat.mm;
|
||||
|
||||
class _StrokePDFPaint extends pw.Widget {
|
||||
List<Stroke> strokes;
|
||||
|
||||
@override
|
||||
void layout(pw.Context context, pw.BoxConstraints constraints,
|
||||
{bool parentUsesSize = false}) {
|
||||
box =
|
||||
PdfRect.fromPoints(PdfPoint.zero, const PdfPoint(_a4width, _a4height));
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(pw.Context context) {
|
||||
super.paint(context);
|
||||
|
||||
for (final stroke in strokes) {
|
||||
context.canvas.setStrokeColor(PdfColor.fromInt(stroke.color.value));
|
||||
for (int i = 0; i < stroke.points.length - 1; i++) {
|
||||
Offset pt1 = stroke.points[i].point * PdfPageFormat.mm;
|
||||
pt1 = Offset(pt1.dx, _a4width - pt1.dy);
|
||||
Offset pt2 = stroke.points[i + 1].point * PdfPageFormat.mm;
|
||||
pt2 = Offset(pt2.dx, _a4width - pt2.dy);
|
||||
|
||||
context.canvas.setLineWidth(stroke.points[i].thickness);
|
||||
context.canvas.drawLine(pt1.dx, pt1.dy, pt2.dx, pt2.dy);
|
||||
context.canvas.strokePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_StrokePDFPaint(this.strokes);
|
||||
}
|
||||
|
||||
void exportPDF(List<Stroke> strokes, String name) async {
|
||||
final pdf = pw.Document();
|
||||
|
||||
const PdfPageFormat a4 = PdfPageFormat(_a4width, _a4height);
|
||||
|
||||
pdf.addPage(pw.MultiPage(
|
||||
pageFormat: a4,
|
||||
build: (context) => [_StrokePDFPaint(strokes)],
|
||||
));
|
||||
|
||||
final path = await getSavePath();
|
||||
final file = File('${path.path}${Platform.pathSeparator}$name');
|
||||
await file.writeAsBytes(await pdf.save(), flush: true);
|
||||
}
|
@ -1,15 +1,26 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
|
||||
import 'app.dart';
|
||||
|
||||
void main() {
|
||||
void main() async {
|
||||
if (defaultTargetPlatform != TargetPlatform.android &&
|
||||
defaultTargetPlatform != TargetPlatform.iOS) {
|
||||
sqfliteFfiInit();
|
||||
databaseFactory = databaseFactoryFfi;
|
||||
}
|
||||
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
Map<Permission, PermissionStatus> statuses =
|
||||
await [Permission.manageExternalStorage, Permission.storage].request();
|
||||
|
||||
if (statuses.containsValue(PermissionStatus.denied)) {
|
||||
// todo some error handling
|
||||
}
|
||||
|
||||
runApp(const MaterialApp(home: App()));
|
||||
}
|
||||
|
@ -34,7 +34,9 @@ class _AllNotesPageState extends State<AllNotesPage> {
|
||||
IconMaterialButton(
|
||||
icon: const Icon(Icons.picture_as_pdf_outlined),
|
||||
color: const Color.fromRGBO(255, 255, 255, .85),
|
||||
onPressed: () {},
|
||||
onPressed: () async {
|
||||
// todo implement pdf import
|
||||
},
|
||||
),
|
||||
IconMaterialButton(
|
||||
icon: const Icon(Icons.search),
|
||||
|
@ -18,11 +18,18 @@ class NoteFile {
|
||||
final path = (await getSavePath()).path + Platform.pathSeparator + filepath;
|
||||
_db = await openDatabase(
|
||||
path,
|
||||
onCreate: (db, version) {
|
||||
return db.execute(
|
||||
'CREATE TABLE strokes(id integer primary key autoincrement, color INTEGER, elevation INTEGER);'
|
||||
'CREATE TABLE points(id integer primary key autoincrement, x INTEGER, y INTEGER, thickness REAL, strokeid INTEGER)',
|
||||
);
|
||||
onCreate: (db, version) async {
|
||||
Batch batch = db.batch();
|
||||
|
||||
batch.execute('DROP TABLE IF EXISTS strokes;');
|
||||
batch.execute('DROP TABLE IF EXISTS points;');
|
||||
|
||||
batch.execute(
|
||||
'CREATE TABLE strokes(id integer primary key autoincrement, color INTEGER, elevation INTEGER)');
|
||||
batch.execute(
|
||||
'CREATE TABLE points(id integer primary key autoincrement, x INTEGER, y INTEGER, thickness REAL, strokeid INTEGER)');
|
||||
await batch.commit();
|
||||
return;
|
||||
},
|
||||
// Set the version. This executes the onCreate function and provides a
|
||||
// path to perform database upgrades and downgrades.
|
||||
|
@ -7,8 +7,11 @@ Future<Directory> getSavePath() async {
|
||||
Directory dbpath;
|
||||
if (defaultTargetPlatform == TargetPlatform.android ||
|
||||
defaultTargetPlatform == TargetPlatform.iOS) {
|
||||
final dir =
|
||||
(await getExternalStorageDirectory())?.parent.parent.parent.parent ??
|
||||
(await getApplicationDocumentsDirectory());
|
||||
dbpath = Directory(
|
||||
'${(await getApplicationDocumentsDirectory()).path}${Platform.pathSeparator}notes');
|
||||
'${dir.path}${Platform.pathSeparator}Documents${Platform.pathSeparator}notes');
|
||||
} else {
|
||||
dbpath = Directory(
|
||||
'${(await getApplicationDocumentsDirectory()).path}${Platform.pathSeparator}notes');
|
||||
|
Reference in New Issue
Block a user