From 2fde531964a19d56b4c9a45254ca0277332a5043 Mon Sep 17 00:00:00 2001 From: randogoth Date: Mon, 24 Feb 2025 15:44:25 +0200 Subject: [PATCH] about text --- lib/codefield.dart | 72 ++++++++ lib/main.dart | 51 +++++- lib/markdown.dart | 81 +++++++++ lib/read_only.dart | 54 ++++++ linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 154 +++++++++++++++++- pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 11 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 lib/codefield.dart create mode 100644 lib/markdown.dart create mode 100644 lib/read_only.dart diff --git a/lib/codefield.dart b/lib/codefield.dart new file mode 100644 index 0000000..b42b26b --- /dev/null +++ b/lib/codefield.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart'; + +class WrappedCodeField extends StatefulWidget { + final CodeController controller; + final bool expands; + final bool wrap; + final TextStyle? textStyle; + final Color? cursorColor; + final EdgeInsets padding; + final bool readOnly; + final FocusNode? focusNode; + + const WrappedCodeField({ + super.key, + required this.controller, + this.expands = false, + this.wrap = true, // ✅ Enable wrapping by default + this.textStyle, + this.cursorColor, + this.padding = EdgeInsets.zero, + this.readOnly = false, + this.focusNode, + }); + + @override + _WrappedCodeFieldState createState() => _WrappedCodeFieldState(); +} + +class _WrappedCodeFieldState extends State { + late FocusNode _focusNode; + + @override + void initState() { + super.initState(); + _focusNode = widget.focusNode ?? FocusNode(); + _focusNode.attach(context, onKeyEvent: _onKeyEvent); + } + + KeyEventResult _onKeyEvent(FocusNode node, KeyEvent event) { + return widget.controller.onKey(event); + } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: widget.padding, + child: TextField( + focusNode: _focusNode, + controller: widget.controller, + expands: widget.expands, + minLines: widget.expands ? null : 1, + maxLines: widget.expands ? null : null, // Allows text to grow dynamically + scrollPhysics: widget.wrap ? const NeverScrollableScrollPhysics() : null, + style: widget.textStyle ?? const TextStyle(fontSize: 16), + cursorColor: widget.cursorColor ?? Colors.white, + decoration: const InputDecoration( + isCollapsed: true, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + ), + readOnly: widget.readOnly, + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index b026fb1..b283e53 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:device_apps/device_apps.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:plasmoid/read_only.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'day.dart'; import 'night.dart'; @@ -356,6 +357,19 @@ class _AppLauncherScreenState extends State { return iconWidget; } + _showInfoPage(BuildContext context, String title, String content) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ReadOnlyPage( + title: title, + content: content, + isDarkMode: widget.settings.darkTheme, + ), + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -383,7 +397,7 @@ class _AppLauncherScreenState extends State { icon: SvgPicture.asset( "assets/plasmoid.svg", width: 30, - color: Colors.orange, + color: Color(0xff38818a), ), onSelected: (String value) { switch (value) { @@ -448,6 +462,9 @@ class _AppLauncherScreenState extends State { autoFocus: !widget.settings.autoFocus, )); break; + case 'About': + _showInfoPage(context, "About", aboutContent); + break; } }, itemBuilder: (BuildContext context) => [ @@ -511,6 +528,13 @@ class _AppLauncherScreenState extends State { title: Text(widget.settings.autoFocus ? 'Disable Auto Focus' : 'Enable Auto Focus'), ), ), + PopupMenuItem( + value: 'About', + child: ListTile( + leading: Icon(Icons.info_outline), + title: Text('About'), + ), + ), ], ), ), @@ -560,3 +584,28 @@ class _AppLauncherScreenState extends State { ); } } + +String aboutContent = """ +**Plasmoid** is a minimalist and opinionated app launcher for Android. + +## Search & Launch: + +Open Plasmoid and start typing in the search bar to filter your apps and shared files by name or tag. +Tap an app to launch it immediately. + +## Tagging: + +Swipe right on any item to edit its tags. For shared files, a tag dialog appears immediately upon sharing. +Tags help you organize items and are searchable using prefixes like @context, #general, or +project. + +## Gestures & Settings: + +Swipe left on an app to view its settings. +Use the menu button (plasmoid) to toggle settings such as icon visibility, color mode, theme, sorting (alphabetically or by last used), and auto-focus. + +--- + +Made with 💚 by randogothimport 'package:plasmoid/texts.dart'; + +Icon by [Game Icons.net](https://game-icons.net/). +"""; diff --git a/lib/markdown.dart b/lib/markdown.dart new file mode 100644 index 0000000..e6efe51 --- /dev/null +++ b/lib/markdown.dart @@ -0,0 +1,81 @@ +import 'package:highlight/highlight.dart'; + +final markdown = Mode(refs: {}, aliases: [ + "md", + "mkdown", + "mkd" +], contains: [ + Mode(className: "section", variants: [ + Mode(begin: "^#\\s{1,6}", end: "\$"), + Mode(begin: "^.+?\\n[=-]{2,}\$") + ]), + Mode(begin: "<", end: ">", subLanguage: ["xml"], relevance: 0), + Mode(className: "bullet", begin: "^\\s*([*+-]|(\\d+\\.))\\s+"), + Mode(className: "strong", begin: "[*_]{2}.+?[*_]{2}"), + Mode( + className: "emphasis", + variants: [Mode(begin: "\\*.+?\\*"), Mode(begin: "_.+?_", relevance: 0)]), + Mode(className: "quote", begin: "^>\\s+", end: "\$"), + Mode(className: "code", variants: [ + Mode(begin: "^```\\w*\\s*\$", end: "^```[ ]*\$"), + Mode(begin: "`.+?`"), + Mode(begin: "^( {4}|\\t)", end: "\$", relevance: 0) + ]), + Mode(begin: "^[-\\*]{3,}", end: "\$"), + Mode( + begin: "\\[.+?\\][\\(\\[].*?[\\)\\]]", + returnBegin: true, + contains: [ + Mode( + className: "string", + begin: "\\[", + end: "\\]", + excludeBegin: true, + returnEnd: true, + relevance: 0), + Mode( + className: "link", + begin: "\\]\\(", + end: "\\)", + excludeBegin: true, + excludeEnd: true), + Mode( + className: "symbol", + begin: "\\]\\[", + end: "\\]", + excludeBegin: true, + excludeEnd: true) + ], + relevance: 10), + Mode(begin: "^\\[[^\\n]+\\]:", returnBegin: true, contains: [ + Mode( + className: "symbol", + begin: "\\[", + end: "\\]", + excludeBegin: true, + excludeEnd: true), + Mode(className: "link", begin: ":\\s*", end: "\$", excludeBegin: true) + ]), + + // Custom Tag Highlighting + Mode( + className: "tag-hash", + begin: "(?<=\\s|^)#[a-zA-Z0-9_]+", + relevance: 10), // Magenta + Mode( + className: "tag-plus", + begin: "(?<=\\s|^)\\+[a-zA-Z0-9_]+", + relevance: 10), // Cyan + Mode( + 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/read_only.dart b/lib/read_only.dart new file mode 100644 index 0000000..2c14485 --- /dev/null +++ b/lib/read_only.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart'; +import 'markdown.dart'; +import 'day.dart'; +import '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: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 15.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Image.asset( + 'assets/plasmoid_fg.png', + width: 200, + ), + ), + SizedBox(height: 20), + CodeTheme( + data: CodeThemeData(styles: theme), + child: WrappedCodeField( + controller: CodeController( + text: content, + language: markdown, + ), + wrap: true, + readOnly: true, + ), + ), + SizedBox(height: 80) + ], + ) + ), + ); + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..f6f23bf 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..f16b4c3 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index b8e2b22..b19945c 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,8 +7,10 @@ import Foundation import path_provider_foundation import shared_preferences_foundation +import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index cb345bf..1f9e914 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + autotrie: + dependency: transitive + description: + name: autotrie + sha256: "55da6faefb53cfcb0abb2f2ca8636123fb40e35286bb57440d2cf467568188f8" + url: "https://pub.dev" + source: hosted + version: "2.0.0" boolean_selector: dependency: transitive description: @@ -41,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" + source: hosted + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -97,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + equatable: + dependency: transitive + description: + name: equatable + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" + url: "https://pub.dev" + source: hosted + version: "2.0.7" fake_async: dependency: transitive description: @@ -126,6 +150,22 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_code_editor: + dependency: "direct main" + description: + name: flutter_code_editor + sha256: "505ad56dcc8a7be4b782c8113574571bc4b9723499b0c1f385b3e2c3fae11f5d" + url: "https://pub.dev" + source: hosted + version: "0.3.2" + flutter_highlight: + dependency: transitive + description: + name: flutter_highlight + sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" + url: "https://pub.dev" + source: hosted + version: "0.7.0" flutter_launcher_icons: dependency: "direct main" description: @@ -168,6 +208,22 @@ packages: url: "https://pub.dev" source: hosted version: "6.2.1" + highlight: + dependency: transitive + description: + name: highlight + sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + hive: + dependency: transitive + description: + name: hive + sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" + url: "https://pub.dev" + source: hosted + version: "2.2.3" http: dependency: transitive description: @@ -224,6 +280,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + linked_scroll_controller: + dependency: transitive + description: + name: linked_scroll_controller + sha256: e6020062bcf4ffc907ee7fd090fa971e65d8dfaac3c62baf601a3ced0b37986a + url: "https://pub.dev" + source: hosted + version: "0.2.0" lints: dependency: transitive description: @@ -256,6 +320,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.15.0" + mocktail: + dependency: transitive + description: + name: mocktail + sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" + url: "https://pub.dev" + source: hosted + version: "1.0.4" path: dependency: transitive description: @@ -352,6 +424,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.1" + scrollable_positioned_list: + dependency: transitive + description: + name: scrollable_positioned_list + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" + url: "https://pub.dev" + source: hosted + version: "0.3.8" shared_preferences: dependency: "direct main" description: @@ -461,6 +541,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.3" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" typed_data: dependency: transitive description: @@ -469,6 +557,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + url_launcher: + dependency: transitive + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" + url: "https://pub.dev" + source: hosted + version: "6.3.14" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" vector_graphics: dependency: transitive description: @@ -543,4 +695,4 @@ packages: version: "3.1.3" sdks: dart: ">=3.6.0 <4.0.0" - flutter: ">=3.24.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index da64d00..65d8954 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: flutter_svg: ^2.0.17 google_fonts: ^6.2.1 flutter_launcher_icons: ^0.14.3 + flutter_code_editor: ^0.3.2 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..4f78848 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..88b22e5 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST