From 750a228921f8e3e24506d68517f4c3491872b281 Mon Sep 17 00:00:00 2001 From: randogoth Date: Sat, 22 Feb 2025 20:59:42 +0200 Subject: [PATCH] added about and help texts, font size slider --- lib/note_editor.dart | 34 +++++++++++++++--- lib/note_list.dart | 50 +++++++++++++++++++++++--- lib/read_only.dart | 67 ++++++++++++++++++++++++++++++++++ lib/texts.dart | 78 ++++++++++++++++++++++++++++++++++++++++ lib/themes/markdown.dart | 8 +++++ lib/themes/night.dart | 2 +- 6 files changed, 230 insertions(+), 9 deletions(-) create mode 100644 lib/read_only.dart create mode 100644 lib/texts.dart diff --git a/lib/note_editor.dart b/lib/note_editor.dart index 44f1dd9..e9e4a46 100644 --- a/lib/note_editor.dart +++ b/lib/note_editor.dart @@ -178,7 +178,7 @@ class _NoteEditorScreenState extends State { PopupMenuItem( value: 'Save', child: ListTile( - leading: Icon(Icons.save), + leading: Icon(Icons.save_outlined), title: Text("Save"), ), ), @@ -186,18 +186,44 @@ class _NoteEditorScreenState extends State { value: 'Toggle Autosave', child: ListTile( leading: Icon(_autoSaveEnabled - ? Icons.toggle_on - : Icons.toggle_off), + ? Icons.alarm_off + : Icons.alarm_on), title: Text(_autoSaveEnabled ? "Disable Autosave" : "Enable Autosave"), ), ), + PopupMenuItem( + enabled: false, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Font Size'), + StatefulBuilder( + builder: (context, setState) { + return Slider( + value: _fontSize, + min: 12.0, + max: 24.0, + divisions: 6, + label: _fontSize.toString(), + onChanged: (newSize) { + setState(() { + _fontSize = newSize; + }); + _updateFontSize(newSize); + }, + ); + }, + ), + ], + ), + ), PopupMenuItem( value: 'Toggle Preview', child: ListTile( leading: - Icon(_isPreviewMode ? Icons.edit : Icons.preview), + Icon(_isPreviewMode ? Icons.edit_note_outlined : Icons.visibility_outlined), title: Text(_isPreviewMode ? "Edit Mode" : "Preview Mode"), ), diff --git a/lib/note_list.dart b/lib/note_list.dart index 295df10..e67bdc8 100644 --- a/lib/note_list.dart +++ b/lib/note_list.dart @@ -9,6 +9,8 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'note_editor.dart'; +import 'read_only.dart'; +import 'texts.dart'; class NoteListScreen extends StatefulWidget { final void Function(bool) toggleTheme; @@ -487,18 +489,36 @@ class _NoteListScreenState extends State { case ':emptytrash': _confirmEmptyTrash(); break; + case ':about': + _showInfoPage(context, "About", aboutContent); + break; + case ':help': + _showInfoPage(context, "Help", helpContent); default: return; // Do nothing for unrecognized commands } searchController.clear(); } + _showInfoPage(BuildContext context, String title, String content) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ReadOnlyPage( + title: title, + content: content, + isDarkMode: widget.isDarkMode, + ), + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Padding( - padding: EdgeInsets.symmetric(horizontal: 15), + padding: EdgeInsets.symmetric(horizontal: 10), child: TextField( enableInteractiveSelection: true, autocorrect: false, @@ -549,7 +569,13 @@ class _NoteListScreenState extends State { case 'Empty Trash': _confirmEmptyTrash(); break; - } + case 'Help': + _showInfoPage(context, "Help", helpContent); + break; + case 'About': + _showInfoPage(context, "About", aboutContent); + break; + } }, itemBuilder: (BuildContext context) => [ PopupMenuItem( @@ -625,6 +651,7 @@ class _NoteListScreenState extends State { title: Text('Set Notes Directory'), ), ), + PopupMenuDivider(), PopupMenuItem( value: 'Empty Trash', child: ListTile( @@ -633,13 +660,28 @@ class _NoteListScreenState extends State { style: TextStyle(color: Colors.redAccent)), ), ), + PopupMenuDivider(), + PopupMenuItem( + value: 'Help', + child: ListTile( + leading: Icon(Icons.help_outline), + title: Text('Help'), + ), + ), + PopupMenuItem( + value: 'About', + child: ListTile( + leading: Icon(Icons.info_outline), + title: Text('About'), + ), + ), ], ), ), ], ), body: Padding( - padding: EdgeInsets.symmetric(horizontal: 15), + padding: EdgeInsets.only(left: 10), child: ListView.builder( itemCount: filteredNotes.length, itemBuilder: (context, index) { @@ -735,4 +777,4 @@ class _NoteListScreenState extends State { ), ); } -} +} \ No newline at end of file diff --git a/lib/read_only.dart b/lib/read_only.dart new file mode 100644 index 0000000..621f9cd --- /dev/null +++ b/lib/read_only.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart'; +import 'themes//markdown.dart'; +import 'themes/day.dart'; +import 'themes/night.dart'; +import 'codefield.dart'; // Ensure this includes WrappedCodeField + +class ReadOnlyPage extends StatelessWidget { + final String title; + final String content; + final bool isDarkMode; + + ReadOnlyPage({ + required this.title, + required this.content, + required this.isDarkMode, + }); + + @override + Widget build(BuildContext context) { + final theme = isDarkMode ? nightTheme : dayTheme; + + return Scaffold( + appBar: AppBar(title: Text(title)), + body: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15.0), + child: title == "About" + ? Column( + children: [ + Center( + child: Image.asset( + 'assets/blaster_fg.png', + width: 200, + ) + ), + CodeTheme( + data: CodeThemeData(styles: theme), + child: SingleChildScrollView( + child: WrappedCodeField( + controller: CodeController( + text: content, + language: markdown, + ), + wrap: true, + readOnly: true, + ), + ), + ), + ] + ) + : CodeTheme( + data: CodeThemeData(styles: theme), + child: SingleChildScrollView( + child: WrappedCodeField( + controller: CodeController( + text: content, + language: markdown, + ), + wrap: true, + readOnly: true, + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/texts.dart b/lib/texts.dart new file mode 100644 index 0000000..15b488d --- /dev/null +++ b/lib/texts.dart @@ -0,0 +1,78 @@ +String helpContent = """ +# Search + +Type to filter notes by title. +Use #tags, +projects, or @contexts to find notes with specific tags. +Start with a / to filter notes within /subdirectories. +Mix text, tags, and folders (/work project #important). + +# Create Notes + +Type the title of a new note in the search bar and hit Enter. +Use /folder/note title to create a note inside a subdirectory. +Subfolders will be automatically created if they don’t exist. + +# Delete Notes + +Swipe a note in the list to the left to move it to the trash. +The trash is a directory in the root folder. +Use :emptytrash or the context menu button to permanently clear deleted notes. + +# Edit Notes + +Enable/disable autosave in the menu. When disabled you can use the Save button in the menu. +If there are unsaved changes when you are leaving the editor, you will be prompted to save. + +# Tag Notes + +Use tags anywhere in the notes and they will be detected. +#tags – General categorization. ++projects – Project-based grouping. +@contexts – Context-specific notes. + +# Context Menu + +Tap the orange blaster at the top right to open the Preferences. + +Here you find toggles to show/hide the tags below the note titles and switch between light and dark themes. + +You can also exclude subdirectories from your search. + +By default the search bar filters by note titles, folders, and tags, but you can also toggle including the file contents. Please be aware that this might slow down the app if you have many files. + +If you prefer to use a different Markdown editor for your files you can toggle that and when you tap a file in the list you can choose what to open the file with. + +By default the notes are saved in the App's own directory which is inaccessible to other apps. If you want to choose your own custom folder for this, you can set it. You will be asked for special permissions to do so. This will enable you to save the notes wherever you want, for example to sync them with a different app. You can also choose a folder that already has notes in it. + +# File Organization + +Root notes are listed above subfolder notes. +Subfolders are ordered by the latest modified file inside them. +Empty folders auto-delete after the last file is removed. + +# Commands + +Use commands by starting with a colon : + +:help – Open this guide. +:tags – Toggle tag visibility. +:day - Switch to light theme. +:night - Switch to dark theme. +:extern – Toggle external editor usage. +:intern – Toggle internal editor usage. +:emptytrash – Permanently delete trashed notes. +:about – Open app information. + + +"""; + +String aboutContent = """ +**Muzzle Velocity** is a fast and minimalist note-taking app inspired by *Notational Velocity* and *Terminal Velocity*. + +It is built for speed and efficiency, eliminating unnecessary UI clutter. Every action should be as fast and frictionless as possible. + +Made with 🧡 by randogoth + +with the invaluable help of +OpenAI's 🤖 ChatGPT +"""; \ No newline at end of file diff --git a/lib/themes/markdown.dart b/lib/themes/markdown.dart index 635d045..e6efe51 100644 --- a/lib/themes/markdown.dart +++ b/lib/themes/markdown.dart @@ -70,4 +70,12 @@ final markdown = Mode(refs: {}, aliases: [ className: "tag-at", begin: "(?<=\\s|^)@[a-zA-Z0-9_]+", relevance: 10), // Yellow + Mode( + className: "keyword", + begin: "(?<=\\s|^):[a-zA-Z0-9_]+", + relevance: 10), + Mode( + className: "variable", + begin: "(?<=\\s|^)\/[a-zA-Z0-9_\/]+", + relevance: 10), // Yellow ]); diff --git a/lib/themes/night.dart b/lib/themes/night.dart index 815b51f..e40f87b 100644 --- a/lib/themes/night.dart +++ b/lib/themes/night.dart @@ -43,7 +43,7 @@ const nightTheme = { 'bullet': TextStyle(color: Color(0xffb5bd68)), 'addition': TextStyle(color: Color(0xffb5bd68)), 'title': TextStyle(color: Color(0xff81a2be)), - 'section': TextStyle(color: Color(0xff81a2be)), + 'section': TextStyle(color: Color(0xff81a2be), fontWeight: FontWeight.w600, fontSize: 18), 'keyword': TextStyle(color: Color(0xffb294bb)), 'selector-tag': TextStyle(color: Color(0xffb294bb)), 'root':