Skip to content

Commit 484f854

Browse files
authored
Merge pull request #34 from adeeteya/checkbox
Checkbox
2 parents a9a978d + 4989151 commit 484f854

File tree

13 files changed

+163
-25
lines changed

13 files changed

+163
-25
lines changed

.github/FUNDING.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
github: [adeeteya]
2-
buy_me_a_coffee: adeeteya
32
patreon: adeeteya
4-
liberapay: adeeteya
3+
open_collective: adeeteya
54
ko_fi: adeeteya
6-
open_collective: adeeteya
5+
liberapay: adeeteya
6+
issuehunt: adeeteya
7+
buy_me_a_coffee: adeeteya
8+
thanks_dev: adeeteya

.github/workflows/build-and-deploy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ jobs:
155155
- name: Upload Windows Release Artifact to GitHub Release
156156
shell: cmd
157157
run: |
158-
gh release upload ${{ inputs.version_number }} D:\a\FlutterMarkdownEditor\FlutterMarkdownEditor\MarkdownEditor-Windows.exe
158+
gh release upload ${{ inputs.version_number }} "%GITHUB_WORKSPACE%\MarkdownEditor-Windows.exe"
159159
env:
160160
GH_TOKEN: ${{ secrets.GH_TOKEN }}
161161

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
🖌️ updated dependencies
1+
Added LaTex support
2+
Added Horizontal Swipe to Switch between Preview and Editing View in Single View Mode
3+
Added Default Folder for Opening and Saving .md files
4+
Added Print/Save as Pdf Option
5+
Added the option to check/uncheck checkboxes in preview mode
6+
Added Convenient way to add tables

README.md

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ Please star⭐ the repo if you like what you see😊.
5454
<a href="https://github.com/adeeteya/FlutterMarkdownEditor/releases/latest/download/MarkdownEditor-Linux-rpm.rpm">
5555
<img alt="Download .rpm" src="https://img.shields.io/static/v1?label=Download&message=.rpm&color=EE0000&style=for-the-badge&logo=redhat&logoColor=white&logoSize=auto">
5656
</a>
57+
<br>
58+
<br>
59+
<a href="https://snapcraft.io/markdown-editor">
60+
<img alt="Get it from the Snap Store" src=https://snapcraft.io/en/dark/install.svg />
61+
</a>
5762
</td>
5863
</tr>
5964

@@ -96,23 +101,33 @@ Please star⭐ the repo if you like what you see😊.
96101
- [x] Horizontal Swipe to Switch between Preview and Editing View in Single View Mode
97102
- [x] Default Folder for Opening and Saving .md files
98103
- [x] Added Print/Save as Pdf Option
104+
- [x] Added the option to check/uncheck checkboxes in preview mode
99105

100106
## 📸 Screenshots
101107

102108
<img alt="Light Mode Image" src="screenshots/screenshot_1.png" height="587px" width="256px"/> <img alt="Dark Mode Image" src="screenshots/screenshot_2.png" height="587px" width="256px"/> <img alt="File Explorer Image" src="screenshots/screenshot_3.png" height="587px" width="256px"/> <img alt="Add Link Image" src="screenshots/screenshot_4.png" height="587px" width="256px"/> <img alt="Markdown Preview Image" src="screenshots/screenshot_5.png" height="587px" width="256px"/> <img alt="Markdown Editor Image" src="screenshots/screenshot_6.png" height="587px" width="256px"/>
103109

104110
## 🔌 Plugins
105111

106-
| Name | Usage |
107-
|-----------------------------------------------------------------------------|-------------------------------------------------------------|
108-
| [**flutter_markdown**](https://pub.dev/packages/flutter_markdown) | To render markdown text |
109-
| [**permission_handler**](https://pub.dev/packages/permission_handler) | To get storage permissions for opening and saving .md files |
110-
| [**url_launcher**](https://pub.dev/packages/url_launcher) | To launch markdown links |
111-
| [**file_picker**](https://pub.dev/packages/file_picker) | To open markdown files directly from the app |
112-
| [**expandable**](https://pub.dev/packages/expandable) | To create expandable header buttons |
113-
| [**flutter_localizations**](https://pub.dev/packages/flutter_localizations) | Internationalizing app |
114-
| [**intl**](https://pub.dev/packages/intl) | Provides internationalization and localization facilities |
115-
| [**flutter_lints**](https://pub.dev/packages/flutter_lints) | For linting |
112+
| Name | Usage |
113+
|---------------------------------------------------------------------------------------------|-------------------------------------------------------------|
114+
| [**expandable**](https://pub.dev/packages/expandable) | To create expandable header buttons |
115+
| [**file_picker**](https://pub.dev/packages/file_picker) | To open markdown files directly from the app |
116+
| [**flutter_localizations**](https://pub.dev/packages/flutter_localizations) | Internationalizing app |
117+
| [**flutter_math_fork**](https://pub.dev/packages/flutter_math_fork) | Help with LaTeX support |
118+
| [**flutter_svg**](https://pub.dev/packages/flutter_svg) | To Display Svg Images |
119+
| [**flutter_widget_from_html_core**](https://pub.dev/packages/flutter_widget_from_html_core) | To add html display support |
120+
| [**html**](https://pub.dev/packages/html) | To help display html format |
121+
| [**htmltopdfwidgets**](https://pub.dev/packages/htmltopdfwidgets) | To convert html to pdf for printing |
122+
| [**intl**](https://pub.dev/packages/intl) | Provides internationalization and localization facilities |
123+
| [**markdown**](https://pub.dev/packages/markdown) | To convert markdown to html format |
124+
| [**markdown_widget**](https://pub.dev/packages/markdown_widget) | To help display markdown/custom markdown |
125+
| [**pdf**](https://pub.dev/packages/pdf) | To help save/create a pdf |
126+
| [**permission_handler**](https://pub.dev/packages/permission_handler) | To get storage permissions for opening and saving .md files |
127+
| [**printing**](https://pub.dev/packages/printing) | To help printing a pdf |
128+
| [**shared_preferences**](https://pub.dev/packages/shared_preferences) | To store device preferences for persistence |
129+
| [**url_launcher**](https://pub.dev/packages/url_launcher) | To launch markdown links |
130+
| [**flutter_lints**](https://pub.dev/packages/flutter_lints) | For linting |
116131

117132
## 🤓 Author
118133

SECURITY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
| Version | Supported |
66
|---------|--------------------|
7+
| 2.0.0 | :white_check_mark: |
78
| 1.4.1 | :white_check_mark: |
89
| 1.4.0 | :white_check_mark: |
910
| 1.3.0 | :white_check_mark: |

lib/home.dart

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22
import 'dart:convert';
33
import 'dart:io';
4+
import 'dart:math' as math;
45

56
import 'package:file_picker/file_picker.dart';
67
import 'package:flutter/foundation.dart';
@@ -10,6 +11,7 @@ import 'package:htmltopdfwidgets/htmltopdfwidgets.dart' as html2pdf;
1011
import 'package:markdown/markdown.dart' as md;
1112
import 'package:markdown_editor/device_preference_notifier.dart';
1213
import 'package:markdown_editor/l10n/generated/app_localizations.dart';
14+
import 'package:markdown_editor/widgets/MarkdownBody/custom_checkbox.dart';
1315
import 'package:markdown_editor/widgets/MarkdownBody/custom_image_config.dart';
1416
import 'package:markdown_editor/widgets/MarkdownBody/custom_text_node.dart';
1517
import 'package:markdown_editor/widgets/MarkdownBody/latex_node.dart';
@@ -33,6 +35,9 @@ class _HomeState extends State<Home> {
3335
static const _methodChannel = MethodChannel(
3436
"com.adeeteya.markdown_editor/channel",
3537
);
38+
static final RegExp _taskListLinePattern = RegExp(
39+
r'^(?:[-+*]|\d+[.)])\s+\[(?: |x|X)\]',
40+
);
3641
String _filePath = "/storage/emulated/0/Download";
3742
String _fileName = 'Markdown';
3843
bool _isPreview = false;
@@ -263,6 +268,7 @@ class _HomeState extends State<Home> {
263268
final config = isDark
264269
? MarkdownConfig.darkConfig
265270
: MarkdownConfig.defaultConfig;
271+
int checkboxIndex = -1;
266272
return Card(
267273
child: SizedBox(
268274
height: double.infinity,
@@ -283,7 +289,22 @@ class _HomeState extends State<Home> {
283289
CustomTextNode(node.textContent, config, visitor),
284290
richTextBuilder: Text.rich,
285291
),
286-
config: config.copy(configs: [CustomImgConfig()]),
292+
config: config.copy(
293+
configs: [
294+
CustomImgConfig(),
295+
CheckBoxConfig(
296+
builder: (checked) {
297+
checkboxIndex++;
298+
final currentIndex = checkboxIndex;
299+
return CustomCheckbox(
300+
key: ValueKey('markdown-task-checkbox-$currentIndex'),
301+
checked: checked,
302+
onChanged: () => _toggleTaskListCheckbox(currentIndex),
303+
);
304+
},
305+
),
306+
],
307+
),
287308
),
288309
),
289310
),
@@ -346,6 +367,70 @@ class _HomeState extends State<Home> {
346367
);
347368
}
348369

370+
List<int> _taskListMarkerPositions(String text) {
371+
final positions = <int>[];
372+
final lines = text.split('\n');
373+
var offset = 0;
374+
375+
for (final line in lines) {
376+
var sanitizedLine = line;
377+
if (sanitizedLine.endsWith('\r')) {
378+
sanitizedLine = sanitizedLine.substring(0, sanitizedLine.length - 1);
379+
}
380+
sanitizedLine = sanitizedLine.trimLeft();
381+
while (sanitizedLine.startsWith('>')) {
382+
sanitizedLine = sanitizedLine.substring(1).trimLeft();
383+
}
384+
if (_taskListLinePattern.hasMatch(sanitizedLine)) {
385+
final bracketIndex = line.indexOf('[');
386+
if (bracketIndex != -1) {
387+
positions.add(offset + bracketIndex);
388+
}
389+
}
390+
offset += line.length + 1;
391+
}
392+
393+
return positions;
394+
}
395+
396+
void _toggleTaskListCheckbox(int index) {
397+
final markerPositions = _taskListMarkerPositions(_inputText);
398+
if (index < 0 || index >= markerPositions.length) {
399+
return;
400+
}
401+
final markerStart = markerPositions[index];
402+
if (markerStart + 2 >= _inputText.length) {
403+
return;
404+
}
405+
final currentState = _inputText[markerStart + 1];
406+
final newState = (currentState == 'x' || currentState == 'X') ? ' ' : 'x';
407+
final updatedText = _inputText.replaceRange(
408+
markerStart,
409+
markerStart + 3,
410+
'[$newState]',
411+
);
412+
final currentSelection = _textEditingController.selection;
413+
final collapsedSelection = currentSelection.isValid
414+
? TextSelection(
415+
baseOffset: math.min(
416+
currentSelection.baseOffset,
417+
updatedText.length,
418+
),
419+
extentOffset: math.min(
420+
currentSelection.extentOffset,
421+
updatedText.length,
422+
),
423+
)
424+
: TextSelection.collapsed(offset: updatedText.length);
425+
setState(() {
426+
_inputText = updatedText;
427+
_textEditingController.value = TextEditingValue(
428+
text: updatedText,
429+
selection: collapsedSelection,
430+
);
431+
});
432+
}
433+
349434
@override
350435
Widget build(BuildContext context) {
351436
return GestureDetector(
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import 'package:flutter/material.dart';
2+
3+
class CustomCheckbox extends StatelessWidget {
4+
final bool checked;
5+
final VoidCallback onChanged;
6+
7+
const CustomCheckbox({
8+
super.key,
9+
required this.checked,
10+
required this.onChanged,
11+
});
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Padding(
16+
padding: const EdgeInsets.symmetric(horizontal: 2),
17+
child: Checkbox(
18+
value: checked,
19+
onChanged: (_) => onChanged(),
20+
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
21+
visualDensity: VisualDensity.compact,
22+
),
23+
);
24+
}
25+
}

lib/widgets/MarkdownBody/custom_image_config.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ class CustomImgConfig extends ImgConfig {
2424
try {
2525
final w = attrs['width'];
2626
final h = attrs['height'];
27-
if (w != null && w.trim().isNotEmpty) width = double.parse(w);
28-
if (h != null && h.trim().isNotEmpty) height = double.parse(h);
27+
if (w != null && w.trim().isNotEmpty) {
28+
width = double.tryParse(w) ?? 0;
29+
}
30+
if (h != null && h.trim().isNotEmpty) {
31+
height = double.tryParse(h) ?? 0;
32+
}
2933
} catch (_) {}
3034

3135
final alt = attrs['alt'] ?? '';

linux/markdown_editor.desktop

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[Desktop Entry]
2-
Version=1.4.1
2+
Version=2.0.0
33
Name=Markdown Editor
44
Comment=Markdown Editor is a lightweight and intuitive app for creating and editing .md files with ease
55
Exec=/usr/bin/markdown-editor

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: A Flutter app to edit and save markdown files
33

44
publish_to: 'none'
55

6-
version: 1.4.1+7
6+
version: 2.0.0+8
77

88
environment:
99
sdk: ^3.9.2

0 commit comments

Comments
 (0)