mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-29 10:17:16 +08:00
Core: Null Safety++
This is a rather huge change. I hope I haven't broken anything.
This commit is contained in:
@ -1,5 +1,3 @@
|
|||||||
// @dart=2.9
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2020-2021 Vishesh Handa <me@vhanda.in>
|
Copyright 2020-2021 Vishesh Handa <me@vhanda.in>
|
||||||
|
|
||||||
@ -86,31 +84,31 @@ enum NoteFileFormat {
|
|||||||
|
|
||||||
class Note with NotesNotifier {
|
class Note with NotesNotifier {
|
||||||
NotesFolderFS parent;
|
NotesFolderFS parent;
|
||||||
String _filePath;
|
String? _filePath;
|
||||||
|
|
||||||
String _title = "";
|
String _title = "";
|
||||||
DateTime _created;
|
DateTime? _created;
|
||||||
DateTime _modified;
|
DateTime? _modified;
|
||||||
String _body = "";
|
String _body = "";
|
||||||
NoteType _type = NoteType.Unknown;
|
NoteType _type = NoteType.Unknown;
|
||||||
Set<String> _tags = {};
|
Set<String> _tags = {};
|
||||||
Map<String, dynamic> _extraProps = {};
|
Map<String, dynamic> _extraProps = {};
|
||||||
|
|
||||||
NoteFileFormat _fileFormat;
|
NoteFileFormat? _fileFormat;
|
||||||
|
|
||||||
MdYamlDoc _data = MdYamlDoc();
|
MdYamlDoc _data = MdYamlDoc();
|
||||||
NoteSerializer noteSerializer;
|
late NoteSerializer noteSerializer;
|
||||||
|
|
||||||
DateTime fileLastModified;
|
DateTime? fileLastModified;
|
||||||
|
|
||||||
var _loadState = NoteLoadState.None;
|
var _loadState = NoteLoadState.None;
|
||||||
var _serializer = MarkdownYAMLCodec();
|
var _serializer = MarkdownYAMLCodec();
|
||||||
|
|
||||||
// Computed from body
|
// Computed from body
|
||||||
String _summary;
|
String? _summary;
|
||||||
List<Link> _links;
|
List<Link>? _links;
|
||||||
Set<String> _inlineTags;
|
Set<String>? _inlineTags;
|
||||||
Set<NoteImage> _images;
|
Set<NoteImage>? _images;
|
||||||
|
|
||||||
static final _mdYamlDocLoader = MdYamlDocLoader();
|
static final _mdYamlDocLoader = MdYamlDocLoader();
|
||||||
static final _linksLoader = LinksLoader();
|
static final _linksLoader = LinksLoader();
|
||||||
@ -150,58 +148,61 @@ class Note with NotesNotifier {
|
|||||||
|
|
||||||
String get filePath {
|
String get filePath {
|
||||||
if (_filePath == null) {
|
if (_filePath == null) {
|
||||||
|
var fp = "";
|
||||||
try {
|
try {
|
||||||
_filePath = p.join(parent.folderPath, _buildFileName());
|
fp = p.join(parent.folderPath, _buildFileName());
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
Log.e("_buildFileName: $e");
|
Log.e("_buildFileName: $e");
|
||||||
logExceptionWarning(e, stackTrace);
|
logExceptionWarning(e, stackTrace);
|
||||||
_filePath = p.join(parent.folderPath, const Uuid().v4());
|
fp = p.join(parent.folderPath, const Uuid().v4());
|
||||||
}
|
}
|
||||||
switch (_fileFormat) {
|
switch (_fileFormat) {
|
||||||
case NoteFileFormat.OrgMode:
|
case NoteFileFormat.OrgMode:
|
||||||
if (!_filePath.toLowerCase().endsWith('.org')) {
|
if (!fp.toLowerCase().endsWith('.org')) {
|
||||||
_filePath += '.org';
|
fp += '.org';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NoteFileFormat.Txt:
|
case NoteFileFormat.Txt:
|
||||||
if (!_filePath.toLowerCase().endsWith('.txt')) {
|
if (!fp.toLowerCase().endsWith('.txt')) {
|
||||||
_filePath += '.txt';
|
fp += '.txt';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NoteFileFormat.Markdown:
|
case NoteFileFormat.Markdown:
|
||||||
default:
|
default:
|
||||||
if (!_filePath.toLowerCase().endsWith('.md')) {
|
if (!fp.toLowerCase().endsWith('.md')) {
|
||||||
_filePath += '.md';
|
fp += '.md';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_filePath = fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _filePath;
|
return _filePath as String;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get fileName {
|
String get fileName {
|
||||||
return p.basename(filePath);
|
return p.basename(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime get created {
|
DateTime? get created {
|
||||||
return _created;
|
return _created;
|
||||||
}
|
}
|
||||||
|
|
||||||
set created(DateTime dt) {
|
set created(DateTime? dt) {
|
||||||
if (!canHaveMetadata) return;
|
if (!canHaveMetadata) return;
|
||||||
|
|
||||||
_created = dt;
|
_created = dt;
|
||||||
_notifyModified();
|
_notifyModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime get modified {
|
DateTime? get modified {
|
||||||
return _modified;
|
return _modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
set modified(DateTime dt) {
|
set modified(DateTime? dt) {
|
||||||
if (!canHaveMetadata) return;
|
if (!canHaveMetadata) return;
|
||||||
|
|
||||||
_modified = dt;
|
_modified = dt;
|
||||||
@ -255,7 +256,6 @@ class Note with NotesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set tags(Set<String> tags) {
|
set tags(Set<String> tags) {
|
||||||
assert(tags != null);
|
|
||||||
if (!canHaveMetadata) return;
|
if (!canHaveMetadata) return;
|
||||||
|
|
||||||
_tags = tags;
|
_tags = tags;
|
||||||
@ -270,16 +270,16 @@ class Note with NotesNotifier {
|
|||||||
var p = InlineTagsProcessor(tagPrefixes: tagPrefixes);
|
var p = InlineTagsProcessor(tagPrefixes: tagPrefixes);
|
||||||
_inlineTags = p.extractTags(body);
|
_inlineTags = p.extractTags(body);
|
||||||
}
|
}
|
||||||
return _inlineTags;
|
return _inlineTags!;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<NoteImage> get images {
|
Set<NoteImage> get images {
|
||||||
if (_loadState != NoteLoadState.Loaded) return {};
|
if (_loadState != NoteLoadState.Loaded) return {};
|
||||||
|
|
||||||
var p = ImageExtractor();
|
var p = ImageExtractor();
|
||||||
_images ??= p.extract(body);
|
_images = p.extract(body);
|
||||||
|
|
||||||
return _images;
|
return _images!;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> get extraProps {
|
Map<String, dynamic> get extraProps {
|
||||||
@ -317,7 +317,7 @@ class Note with NotesNotifier {
|
|||||||
return body.isEmpty;
|
return body.isEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get summary {
|
String? get summary {
|
||||||
if (_loadState != NoteLoadState.Loaded) return "";
|
if (_loadState != NoteLoadState.Loaded) return "";
|
||||||
|
|
||||||
_summary ??= stripMarkdownFormatting(body);
|
_summary ??= stripMarkdownFormatting(body);
|
||||||
@ -330,13 +330,13 @@ class Note with NotesNotifier {
|
|||||||
|
|
||||||
Future<NoteLoadState> load() async {
|
Future<NoteLoadState> load() async {
|
||||||
assert(_filePath != null);
|
assert(_filePath != null);
|
||||||
assert(_filePath.isNotEmpty);
|
assert(_filePath!.isNotEmpty);
|
||||||
|
|
||||||
if (_loadState == NoteLoadState.Loading) {
|
if (_loadState == NoteLoadState.Loading) {
|
||||||
return _loadState;
|
return _loadState;
|
||||||
}
|
}
|
||||||
|
|
||||||
final file = File(_filePath);
|
final file = File(_filePath!);
|
||||||
if (_loadState == NoteLoadState.Loaded) {
|
if (_loadState == NoteLoadState.Loaded) {
|
||||||
try {
|
try {
|
||||||
var fileLastModified = file.lastModifiedSync();
|
var fileLastModified = file.lastModifiedSync();
|
||||||
@ -346,7 +346,7 @@ class Note with NotesNotifier {
|
|||||||
this.fileLastModified = fileLastModified;
|
this.fileLastModified = fileLastModified;
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
if (e is FileSystemException &&
|
if (e is FileSystemException &&
|
||||||
e.osError.errorCode == 2 /* File Not Found */) {
|
e.osError!.errorCode == 2 /* File Not Found */) {
|
||||||
_loadState = NoteLoadState.NotExists;
|
_loadState = NoteLoadState.NotExists;
|
||||||
_notifyModified();
|
_notifyModified();
|
||||||
return _loadState;
|
return _loadState;
|
||||||
@ -360,14 +360,15 @@ class Note with NotesNotifier {
|
|||||||
Log.d("Note modified: $_filePath");
|
Log.d("Note modified: $_filePath");
|
||||||
}
|
}
|
||||||
|
|
||||||
var fpLowerCase = _filePath.toLowerCase();
|
var fpLowerCase = _filePath!.toLowerCase();
|
||||||
var isMarkdown = fpLowerCase.endsWith('.md');
|
var isMarkdown = fpLowerCase.endsWith('.md');
|
||||||
var isTxt = fpLowerCase.endsWith('.txt');
|
var isTxt = fpLowerCase.endsWith('.txt');
|
||||||
var isOrg = fpLowerCase.endsWith('.org');
|
var isOrg = fpLowerCase.endsWith('.org');
|
||||||
|
|
||||||
if (isMarkdown) {
|
if (isMarkdown) {
|
||||||
try {
|
try {
|
||||||
data = await _mdYamlDocLoader.loadDoc(_filePath);
|
var dataMaybe = await _mdYamlDocLoader.loadDoc(_filePath!);
|
||||||
|
data = dataMaybe!;
|
||||||
_fileFormat = NoteFileFormat.Markdown;
|
_fileFormat = NoteFileFormat.Markdown;
|
||||||
} on MdYamlDocNotFoundException catch (_) {
|
} on MdYamlDocNotFoundException catch (_) {
|
||||||
_loadState = NoteLoadState.NotExists;
|
_loadState = NoteLoadState.NotExists;
|
||||||
@ -382,7 +383,7 @@ class Note with NotesNotifier {
|
|||||||
}
|
}
|
||||||
} else if (isTxt) {
|
} else if (isTxt) {
|
||||||
try {
|
try {
|
||||||
body = await File(_filePath).readAsString();
|
body = await File(_filePath!).readAsString();
|
||||||
_fileFormat = NoteFileFormat.Txt;
|
_fileFormat = NoteFileFormat.Txt;
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
logExceptionWarning(e, stackTrace);
|
logExceptionWarning(e, stackTrace);
|
||||||
@ -393,7 +394,7 @@ class Note with NotesNotifier {
|
|||||||
}
|
}
|
||||||
} else if (isOrg) {
|
} else if (isOrg) {
|
||||||
try {
|
try {
|
||||||
body = await File(_filePath).readAsString();
|
body = await File(_filePath!).readAsString();
|
||||||
_fileFormat = NoteFileFormat.OrgMode;
|
_fileFormat = NoteFileFormat.OrgMode;
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
logExceptionWarning(e, stackTrace);
|
logExceptionWarning(e, stackTrace);
|
||||||
@ -417,10 +418,6 @@ class Note with NotesNotifier {
|
|||||||
|
|
||||||
// FIXME: What about error handling?
|
// FIXME: What about error handling?
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
assert(_data != null);
|
|
||||||
assert(_data.body != null);
|
|
||||||
assert(_data.props != null);
|
|
||||||
|
|
||||||
var file = File(filePath);
|
var file = File(filePath);
|
||||||
var contents = _serializer.encode(data);
|
var contents = _serializer.encode(data);
|
||||||
// Make sure all docs end with a \n
|
// Make sure all docs end with a \n
|
||||||
@ -439,7 +436,7 @@ class Note with NotesNotifier {
|
|||||||
Future<void> remove() async {
|
Future<void> remove() async {
|
||||||
assert(_filePath != null);
|
assert(_filePath != null);
|
||||||
|
|
||||||
var file = File(_filePath);
|
var file = File(filePath);
|
||||||
await file.delete();
|
await file.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,8 +534,12 @@ class Note with NotesNotifier {
|
|||||||
if (imageSpec == '.') {
|
if (imageSpec == '.') {
|
||||||
baseFolder = parent.folderPath;
|
baseFolder = parent.folderPath;
|
||||||
} else {
|
} else {
|
||||||
baseFolder = parent.rootFolder.getFolderWithSpec(imageSpec).folderPath;
|
var folder = parent.rootFolder.getFolderWithSpec(imageSpec);
|
||||||
baseFolder ??= parent.folderPath;
|
if (folder != null) {
|
||||||
|
baseFolder = folder.folderPath;
|
||||||
|
} else {
|
||||||
|
baseFolder = parent.folderPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageFileName = p.basename(file.path);
|
var imageFileName = p.basename(file.path);
|
||||||
@ -567,9 +568,6 @@ class Note with NotesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String pathSpec() {
|
String pathSpec() {
|
||||||
if (parent == null) {
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
return p.join(parent.pathSpec(), fileName);
|
return p.join(parent.pathSpec(), fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,7 +588,6 @@ class Note with NotesNotifier {
|
|||||||
} else {
|
} else {
|
||||||
return toSimpleDateTime(date);
|
return toSimpleDateTime(date);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case NoteFileNameFormat.Iso8601:
|
case NoteFileNameFormat.Iso8601:
|
||||||
return toIso8601(date);
|
return toIso8601(date);
|
||||||
case NoteFileNameFormat.Iso8601WithTimeZone:
|
case NoteFileNameFormat.Iso8601WithTimeZone:
|
||||||
@ -606,20 +603,20 @@ class Note with NotesNotifier {
|
|||||||
return date.toString();
|
return date.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Link>> fetchLinks() async {
|
Future<List<Link>?> fetchLinks() async {
|
||||||
if (_links != null) {
|
if (_links != null) {
|
||||||
return _links;
|
return _links;
|
||||||
}
|
}
|
||||||
|
|
||||||
_links = await _linksLoader.parseLinks(body: _body, filePath: _filePath);
|
_links = await _linksLoader.parseLinks(body: _body, filePath: _filePath!);
|
||||||
return _links;
|
return _links;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Link> links() {
|
List<Link>? links() {
|
||||||
return _links;
|
return _links;
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteFileFormat get fileFormat {
|
NoteFileFormat? get fileFormat {
|
||||||
return _fileFormat;
|
return _fileFormat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// @dart=2.9
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -9,25 +7,27 @@ typedef NoteModificationCallback = void Function(Note note);
|
|||||||
typedef NoteRenameCallback = void Function(Note note, String oldPath);
|
typedef NoteRenameCallback = void Function(Note note, String oldPath);
|
||||||
|
|
||||||
class NotesNotifier implements ChangeNotifier {
|
class NotesNotifier implements ChangeNotifier {
|
||||||
var _modListeners = ObserverList<NoteModificationCallback>();
|
ObserverList<NoteModificationCallback>? _modListeners =
|
||||||
var _renameListeners = ObserverList<NoteRenameCallback>();
|
ObserverList<NoteModificationCallback>();
|
||||||
|
ObserverList<NoteRenameCallback>? _renameListeners =
|
||||||
|
ObserverList<NoteRenameCallback>();
|
||||||
|
|
||||||
void addModifiedListener(NoteModificationCallback listener) {
|
void addModifiedListener(NoteModificationCallback listener) {
|
||||||
_modListeners.add(listener);
|
_modListeners?.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeModifiedListener(NoteModificationCallback listener) {
|
void removeModifiedListener(NoteModificationCallback listener) {
|
||||||
assert(_modListeners.contains(listener));
|
assert(_modListeners!.contains(listener));
|
||||||
_modListeners.remove(listener);
|
_modListeners?.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRenameListener(NoteRenameCallback listener) {
|
void addRenameListener(NoteRenameCallback listener) {
|
||||||
_renameListeners.add(listener);
|
_renameListeners?.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeRenameListener(NoteRenameCallback listener) {
|
void removeRenameListener(NoteRenameCallback listener) {
|
||||||
assert(_renameListeners.contains(listener));
|
assert(_renameListeners!.contains(listener));
|
||||||
_renameListeners.remove(listener);
|
_renameListeners?.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
@ -42,7 +42,7 @@ class NotesNotifier implements ChangeNotifier {
|
|||||||
//
|
//
|
||||||
// ChangeNotifier implementation - How to not duplicate this?
|
// ChangeNotifier implementation - How to not duplicate this?
|
||||||
//
|
//
|
||||||
ObserverList<VoidCallback> _listeners = ObserverList<VoidCallback>();
|
ObserverList<VoidCallback>? _listeners = ObserverList<VoidCallback>();
|
||||||
|
|
||||||
bool _debugAssertNotDisposed() {
|
bool _debugAssertNotDisposed() {
|
||||||
assert(() {
|
assert(() {
|
||||||
@ -77,7 +77,7 @@ class NotesNotifier implements ChangeNotifier {
|
|||||||
@override
|
@override
|
||||||
bool get hasListeners {
|
bool get hasListeners {
|
||||||
assert(_debugAssertNotDisposed());
|
assert(_debugAssertNotDisposed());
|
||||||
return _listeners.isNotEmpty;
|
return _listeners!.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a closure to be called when the object changes.
|
/// Register a closure to be called when the object changes.
|
||||||
@ -86,7 +86,7 @@ class NotesNotifier implements ChangeNotifier {
|
|||||||
@override
|
@override
|
||||||
void addListener(VoidCallback listener) {
|
void addListener(VoidCallback listener) {
|
||||||
assert(_debugAssertNotDisposed());
|
assert(_debugAssertNotDisposed());
|
||||||
_listeners.add(listener);
|
_listeners!.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a previously registered closure from the list of closures that are
|
/// Remove a previously registered closure from the list of closures that are
|
||||||
@ -111,7 +111,7 @@ class NotesNotifier implements ChangeNotifier {
|
|||||||
@override
|
@override
|
||||||
void removeListener(VoidCallback listener) {
|
void removeListener(VoidCallback listener) {
|
||||||
assert(_debugAssertNotDisposed());
|
assert(_debugAssertNotDisposed());
|
||||||
_listeners.remove(listener);
|
_listeners!.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call all the registered listeners.
|
/// Call all the registered listeners.
|
||||||
@ -136,10 +136,10 @@ class NotesNotifier implements ChangeNotifier {
|
|||||||
assert(_debugAssertNotDisposed());
|
assert(_debugAssertNotDisposed());
|
||||||
if (_listeners != null) {
|
if (_listeners != null) {
|
||||||
final List<VoidCallback> localListeners =
|
final List<VoidCallback> localListeners =
|
||||||
List<VoidCallback>.from(_listeners);
|
List<VoidCallback>.from(_listeners!);
|
||||||
for (VoidCallback listener in localListeners) {
|
for (VoidCallback listener in localListeners) {
|
||||||
try {
|
try {
|
||||||
if (_listeners.contains(listener)) {
|
if (_listeners!.contains(listener)) {
|
||||||
listener();
|
listener();
|
||||||
}
|
}
|
||||||
} catch (exception, stack) {
|
} catch (exception, stack) {
|
||||||
@ -165,10 +165,11 @@ class NotesNotifier implements ChangeNotifier {
|
|||||||
void notifyModifiedListeners(Note note) {
|
void notifyModifiedListeners(Note note) {
|
||||||
assert(_debugAssertNotDisposed());
|
assert(_debugAssertNotDisposed());
|
||||||
if (_modListeners != null) {
|
if (_modListeners != null) {
|
||||||
final localListeners = List<NoteModificationCallback>.from(_modListeners);
|
final localListeners =
|
||||||
|
List<NoteModificationCallback>.from(_modListeners!);
|
||||||
for (var listener in localListeners) {
|
for (var listener in localListeners) {
|
||||||
try {
|
try {
|
||||||
if (_modListeners.contains(listener)) {
|
if (_modListeners!.contains(listener)) {
|
||||||
listener(note);
|
listener(note);
|
||||||
}
|
}
|
||||||
} catch (exception, stack) {
|
} catch (exception, stack) {
|
||||||
@ -194,10 +195,10 @@ class NotesNotifier implements ChangeNotifier {
|
|||||||
void notifyRenameListeners(Note note, String oldPath) {
|
void notifyRenameListeners(Note note, String oldPath) {
|
||||||
assert(_debugAssertNotDisposed());
|
assert(_debugAssertNotDisposed());
|
||||||
if (_renameListeners != null) {
|
if (_renameListeners != null) {
|
||||||
final localListeners = List<NoteRenameCallback>.from(_renameListeners);
|
final localListeners = List<NoteRenameCallback>.from(_renameListeners!);
|
||||||
for (var listener in localListeners) {
|
for (var listener in localListeners) {
|
||||||
try {
|
try {
|
||||||
if (_renameListeners.contains(listener)) {
|
if (_renameListeners!.contains(listener)) {
|
||||||
listener(note, oldPath);
|
listener(note, oldPath);
|
||||||
}
|
}
|
||||||
} catch (exception, stack) {
|
} catch (exception, stack) {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// @dart=2.9
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2020-2021 Vishesh Handa <me@vhanda.in>
|
Copyright 2020-2021 Vishesh Handa <me@vhanda.in>
|
||||||
|
|
||||||
@ -65,18 +63,18 @@ class NoteSerializer implements NoteSerializerInterface {
|
|||||||
data.body = emojiParser.unemojify(note.body);
|
data.body = emojiParser.unemojify(note.body);
|
||||||
|
|
||||||
if (note.created != null) {
|
if (note.created != null) {
|
||||||
data.props[settings.createdKey] = toIso8601WithTimezone(note.created);
|
data.props[settings.createdKey] = toIso8601WithTimezone(note.created!);
|
||||||
} else {
|
} else {
|
||||||
data.props.remove(settings.createdKey);
|
data.props.remove(settings.createdKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note.modified != null) {
|
if (note.modified != null) {
|
||||||
data.props[settings.modifiedKey] = toIso8601WithTimezone(note.modified);
|
data.props[settings.modifiedKey] = toIso8601WithTimezone(note.modified!);
|
||||||
} else {
|
} else {
|
||||||
data.props.remove(settings.modifiedKey);
|
data.props.remove(settings.modifiedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note.title != null) {
|
if (note.title.isNotEmpty) {
|
||||||
var title = emojiParser.unemojify(note.title.trim());
|
var title = emojiParser.unemojify(note.title.trim());
|
||||||
if (settings.titleSettings == SettingsTitle.InH1) {
|
if (settings.titleSettings == SettingsTitle.InH1) {
|
||||||
if (title.isNotEmpty) {
|
if (title.isNotEmpty) {
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
// @dart=2.9
|
|
||||||
|
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
@ -24,7 +21,7 @@ class IgnoredFile {
|
|||||||
String filePath;
|
String filePath;
|
||||||
IgnoreReason reason;
|
IgnoreReason reason;
|
||||||
|
|
||||||
IgnoredFile({@required this.filePath, @required this.reason});
|
IgnoredFile({required this.filePath, required this.reason});
|
||||||
|
|
||||||
String get fileName {
|
String get fileName {
|
||||||
return p.basename(filePath);
|
return p.basename(filePath);
|
||||||
@ -32,7 +29,7 @@ class IgnoredFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
||||||
final NotesFolderFS _parent;
|
final NotesFolderFS? _parent;
|
||||||
String _folderPath;
|
String _folderPath;
|
||||||
var _lock = Lock();
|
var _lock = Lock();
|
||||||
|
|
||||||
@ -54,9 +51,9 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
NotesFolder get parent => _parent;
|
NotesFolder? get parent => _parent;
|
||||||
|
|
||||||
NotesFolderFS get parentFS => _parent;
|
NotesFolderFS? get parentFS => _parent;
|
||||||
|
|
||||||
void _entityChanged() {
|
void _entityChanged() {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -190,7 +187,7 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
|||||||
futures.add(f);
|
futures.add(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Future.wait(futures);
|
await Future.wait(futures);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> load() async {
|
Future<void> load() async {
|
||||||
@ -418,7 +415,7 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
|||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return p.join(parent.pathSpec(), name);
|
return p.join(parent!.pathSpec(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -448,7 +445,7 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
NotesFolderFS getFolderWithSpec(String spec) {
|
NotesFolderFS? getFolderWithSpec(String spec) {
|
||||||
if (pathSpec() == spec) {
|
if (pathSpec() == spec) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -465,12 +462,12 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
|||||||
NotesFolderFS get rootFolder {
|
NotesFolderFS get rootFolder {
|
||||||
var folder = this;
|
var folder = this;
|
||||||
while (folder.parent != null) {
|
while (folder.parent != null) {
|
||||||
folder = folder.parent;
|
folder = folder.parent as NotesFolderFS;
|
||||||
}
|
}
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
Note getNoteWithSpec(String spec) {
|
Note? getNoteWithSpec(String spec) {
|
||||||
var parts = spec.split(p.separator);
|
var parts = spec.split(p.separator);
|
||||||
var folder = this;
|
var folder = this;
|
||||||
while (parts.length != 1) {
|
while (parts.length != 1) {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// @dart=2.9
|
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
@ -160,7 +158,7 @@ int _sortCreatedDesc(Note a, Note b) {
|
|||||||
if (bDt == null && aDt == null) {
|
if (bDt == null && aDt == null) {
|
||||||
return a.fileName.compareTo(b.fileName);
|
return a.fileName.compareTo(b.fileName);
|
||||||
}
|
}
|
||||||
return bDt.compareTo(aDt);
|
return bDt!.compareTo(aDt!);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _sortModifiedDesc(Note a, Note b) {
|
int _sortModifiedDesc(Note a, Note b) {
|
||||||
@ -175,12 +173,12 @@ int _sortModifiedDesc(Note a, Note b) {
|
|||||||
if (bDt == null && aDt == null) {
|
if (bDt == null && aDt == null) {
|
||||||
return a.fileName.compareTo(b.fileName);
|
return a.fileName.compareTo(b.fileName);
|
||||||
}
|
}
|
||||||
return bDt.compareTo(aDt);
|
return bDt!.compareTo(aDt!);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _sortTitleAsc(Note a, Note b) {
|
int _sortTitleAsc(Note a, Note b) {
|
||||||
var aTitleExists = a.title != null && a.title.isNotEmpty;
|
var aTitleExists = a.title.isNotEmpty;
|
||||||
var bTitleExists = b.title != null && b.title.isNotEmpty;
|
var bTitleExists = b.title.isNotEmpty;
|
||||||
|
|
||||||
if (!aTitleExists && bTitleExists) {
|
if (!aTitleExists && bTitleExists) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// @dart=2.9
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
@ -30,8 +28,8 @@ Future<void> initSentry() async {
|
|||||||
Future<SentryEvent> get _environmentEvent async {
|
Future<SentryEvent> get _environmentEvent async {
|
||||||
final packageInfo = await PackageInfo.fromPlatform();
|
final packageInfo = await PackageInfo.fromPlatform();
|
||||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||||
SentryOperatingSystem os;
|
SentryOperatingSystem? os;
|
||||||
SentryDevice device;
|
SentryDevice? device;
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
final androidInfo = await deviceInfoPlugin.androidInfo;
|
final androidInfo = await deviceInfoPlugin.androidInfo;
|
||||||
os = SentryOperatingSystem(
|
os = SentryOperatingSystem(
|
||||||
@ -77,19 +75,19 @@ void flutterOnErrorHandler(FlutterErrorDetails details) {
|
|||||||
if (reportCrashes == true) {
|
if (reportCrashes == true) {
|
||||||
// vHanda: This doesn't always call our zone error handler, why?
|
// vHanda: This doesn't always call our zone error handler, why?
|
||||||
// Zone.current.handleUncaughtError(details.exception, details.stack);
|
// Zone.current.handleUncaughtError(details.exception, details.stack);
|
||||||
reportError(details.exception, details.stack);
|
reportError(details.exception, details.stack ?? StackTrace.current);
|
||||||
} else {
|
} else {
|
||||||
FlutterError.dumpErrorToConsole(details);
|
FlutterError.dumpErrorToConsole(details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get reportCrashes => _reportCrashes ??= _initReportCrashes();
|
bool get reportCrashes => _reportCrashes ??= _initReportCrashes();
|
||||||
bool _reportCrashes;
|
bool? _reportCrashes;
|
||||||
bool _initReportCrashes() {
|
bool _initReportCrashes() {
|
||||||
return !JournalApp.isInDebugMode && AppSettings.instance.collectCrashReports;
|
return !JournalApp.isInDebugMode && AppSettings.instance.collectCrashReports;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> reportError(Object error, StackTrace stackTrace) async {
|
Future<void> reportError(dynamic error, StackTrace stackTrace) async {
|
||||||
Log.e("Uncaught Exception", ex: error, stacktrace: stackTrace);
|
Log.e("Uncaught Exception", ex: error, stacktrace: stackTrace);
|
||||||
|
|
||||||
if (reportCrashes) {
|
if (reportCrashes) {
|
||||||
@ -124,8 +122,8 @@ Future<void> logExceptionWarning(Object e, StackTrace stackTrace) async {
|
|||||||
List<Breadcrumb> breadcrumbs = [];
|
List<Breadcrumb> breadcrumbs = [];
|
||||||
|
|
||||||
void captureErrorBreadcrumb({
|
void captureErrorBreadcrumb({
|
||||||
@required String name,
|
required String name,
|
||||||
Map<String, String> parameters,
|
required Map<String, String> parameters,
|
||||||
}) {
|
}) {
|
||||||
var b = Breadcrumb(
|
var b = Breadcrumb(
|
||||||
message: name,
|
message: name,
|
||||||
@ -136,19 +134,20 @@ void captureErrorBreadcrumb({
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> captureSentryException(
|
Future<void> captureSentryException(
|
||||||
Object exception,
|
dynamic exception,
|
||||||
StackTrace stackTrace, {
|
StackTrace stackTrace, {
|
||||||
SentryLevel level = SentryLevel.error,
|
SentryLevel level = SentryLevel.error,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
await initSentry();
|
await initSentry();
|
||||||
final event = (await _environmentEvent).copyWith(
|
final event = (await _environmentEvent).copyWith(
|
||||||
exception: exception,
|
throwable: exception,
|
||||||
breadcrumbs: breadcrumbs,
|
breadcrumbs: breadcrumbs,
|
||||||
level: level,
|
level: level,
|
||||||
);
|
);
|
||||||
|
|
||||||
return Sentry.captureEvent(event, stackTrace: Trace.from(stackTrace).terse);
|
await Sentry.captureEvent(event, stackTrace: Trace.from(stackTrace).terse);
|
||||||
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Failed to report with Sentry: $e");
|
print("Failed to report with Sentry: $e");
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,10 @@ import 'package:gitjournal/screens/note_editor.dart';
|
|||||||
import 'package:gitjournal/settings.dart';
|
import 'package:gitjournal/settings.dart';
|
||||||
import 'package:gitjournal/utils.dart';
|
import 'package:gitjournal/utils.dart';
|
||||||
import 'package:gitjournal/utils/logger.dart';
|
import 'package:gitjournal/utils/logger.dart';
|
||||||
|
import 'common_types.dart';
|
||||||
import 'standard_view.dart';
|
import 'standard_view.dart';
|
||||||
|
|
||||||
enum FolderViewType {
|
export 'common_types.dart';
|
||||||
Standard,
|
|
||||||
Journal,
|
|
||||||
Card,
|
|
||||||
Grid,
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget buildFolderView({
|
Widget buildFolderView({
|
||||||
@required FolderViewType viewType,
|
@required FolderViewType viewType,
|
||||||
|
@ -29,7 +29,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/core/sorting_mode.dart';
|
import 'package:gitjournal/core/sorting_mode.dart';
|
||||||
import 'package:gitjournal/folder_views/common.dart';
|
import 'package:gitjournal/folder_views/common_types.dart';
|
||||||
import 'package:gitjournal/screens/note_editor.dart';
|
import 'package:gitjournal/screens/note_editor.dart';
|
||||||
|
|
||||||
const DEFAULT_ID = "0";
|
const DEFAULT_ID = "0";
|
||||||
|
Reference in New Issue
Block a user