Toggle navigation
Toggle navigation
This project
Loading...
Sign in
flutter_package
/
gpt_markdown
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
saminsohag
2024-12-12 20:53:54 +0600
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
c3dc6e6195acdaac38695cb17e8aac82996dfeb8
c3dc6e61
1 parent
a91f040a
theme extantions added
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
424 additions
and
12 deletions
gpt_markdown/CHANGELOG.md
gpt_markdown/example/lib/main.dart
gpt_markdown/example/lib/selectable_adapter.dart
gpt_markdown/example/pubspec.lock
gpt_markdown/example/pubspec.yaml
gpt_markdown/lib/markdown_component.dart
gpt_markdown/lib/theme.dart
gpt_markdown/pubspec.yaml
gpt_markdown/CHANGELOG.md
View file @
c3dc6e6
## 0.1.11
*
`GptMarkdownTheme` and `GptMarkdownThemeData`
classes added.
## 0.1.10
*
components are now selectable.
...
...
gpt_markdown/example/lib/main.dart
View file @
c3dc6e6
...
...
@@ -4,7 +4,9 @@ import 'package:desktop_drop/desktop_drop.dart';
import
'package:flutter/material.dart'
;
import
'package:gpt_markdown/gpt_markdown.dart'
;
import
'package:flutter_math_fork/flutter_math.dart'
;
import
'package:gpt_markdown/theme.dart'
;
import
'package:watcher/watcher.dart'
;
import
'selectable_adapter.dart'
;
void
main
(
)
{
runApp
(
const
MyApp
());
...
...
@@ -34,7 +36,11 @@ class _MyAppState extends State<MyApp> {
useMaterial3:
true
,
brightness:
Brightness
.
dark
,
colorSchemeSeed:
Colors
.
blue
,
extensions:
[
GptMarkdownThemeData
(
highlightColor:
Colors
.
red
,
),
]),
home:
MyHomePage
(
title:
'GptMarkdown'
,
onPressed:
()
{
...
...
@@ -147,7 +153,11 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
@override
Widget build(BuildContext context) {
return Scaffold(
return GptMarkdownTheme(
gptThemeData: GptMarkdownTheme.of(context).copyWith(
highlightColor: Colors.purple,
),
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
...
...
@@ -180,8 +190,8 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
onPressed: () => setState(() {
writingMod = !writingMod;
}),
icon:
Icon(writingMod ? Icons.arrow_drop_down : Icons.arrow_drop_up),
icon: Icon(
writingMod ? Icons.arrow_drop_down : Icons.arrow_drop_up),
),
],
),
...
...
@@ -211,7 +221,8 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Theme.of(context).colorScheme.outline),
color:
Theme.of(context).colorScheme.outline),
),
child: Theme(
data: Theme.of(context),
...
...
@@ -324,6 +335,10 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
),
);
}
child = SelectableAdapter(
selectedText: tex,
child: Math.tex(tex),
);
child = InkWell(
onTap: () {
debugPrint("Hello world");
...
...
@@ -346,13 +361,16 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
borderRadius:
BorderRadius.circular(10),
),
child: Center(child: Text("
$value
")),
child:
Center(child: Text("
$value
")),
),
);
},
);
if (selectable) {
child = SelectionArea(child: child);
child = SelectionArea(
child: child,
);
}
return child;
},
...
...
@@ -384,6 +402,7 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
],
),
),
),
);
}
}
...
...
gpt_markdown/example/lib/selectable_adapter.dart
0 → 100644
View file @
c3dc6e6
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
class
SelectableAdapter
extends
StatelessWidget
{
const
SelectableAdapter
(
{
super
.
key
,
required
this
.
selectedText
,
required
this
.
child
});
final
Widget
child
;
final
String
selectedText
;
@override
Widget
build
(
BuildContext
context
)
{
final
SelectionRegistrar
?
registrar
=
SelectionContainer
.
maybeOf
(
context
);
if
(
registrar
==
null
)
{
return
child
;
}
return
MouseRegion
(
cursor:
SystemMouseCursors
.
text
,
child:
_SelectableAdapter
(
registrar:
registrar
,
selectedText:
selectedText
,
child:
child
,
),
);
}
}
class
_SelectableAdapter
extends
SingleChildRenderObjectWidget
{
const
_SelectableAdapter
({
required
this
.
registrar
,
required
Widget
child
,
required
this
.
selectedText
,
})
:
super
(
child:
child
);
final
SelectionRegistrar
registrar
;
final
String
selectedText
;
@override
_RenderSelectableAdapter
createRenderObject
(
BuildContext
context
)
{
return
_RenderSelectableAdapter
(
DefaultSelectionStyle
.
of
(
context
).
selectionColor
!,
selectedText
,
registrar
,
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
_RenderSelectableAdapter
renderObject
)
{
renderObject
..
selectionColor
=
DefaultSelectionStyle
.
of
(
context
).
selectionColor
!
..
registrar
=
registrar
;
}
}
class
_RenderSelectableAdapter
extends
RenderProxyBox
with
Selectable
,
SelectionRegistrant
{
String
selectionText
;
_RenderSelectableAdapter
(
Color
selectionColor
,
this
.
selectionText
,
SelectionRegistrar
registrar
,
)
:
_selectionColor
=
selectionColor
,
_geometry
=
ValueNotifier
<
SelectionGeometry
>(
_noSelection
)
{
this
.
registrar
=
registrar
;
_geometry
.
addListener
(
markNeedsPaint
);
}
static
const
SelectionGeometry
_noSelection
=
SelectionGeometry
(
status:
SelectionStatus
.
none
,
hasContent:
true
);
final
ValueNotifier
<
SelectionGeometry
>
_geometry
;
Color
get
selectionColor
=>
_selectionColor
;
late
Color
_selectionColor
;
set
selectionColor
(
Color
value
)
{
if
(
_selectionColor
==
value
)
{
return
;
}
_selectionColor
=
value
;
markNeedsPaint
();
}
// ValueListenable APIs
@override
void
addListener
(
VoidCallback
listener
)
=>
_geometry
.
addListener
(
listener
);
@override
void
removeListener
(
VoidCallback
listener
)
=>
_geometry
.
removeListener
(
listener
);
@override
SelectionGeometry
get
value
=>
_geometry
.
value
;
// Selectable APIs.
@override
List
<
Rect
>
get
boundingBoxes
=>
<
Rect
>[
paintBounds
];
// Adjust this value to enlarge or shrink the selection highlight.
static
const
double
_padding
=
0.0
;
Rect
_getSelectionHighlightRect
()
{
return
Rect
.
fromLTWH
(
0
-
_padding
,
0
-
_padding
,
size
.
width
+
_padding
*
2
,
size
.
height
+
_padding
*
2
);
}
Offset
?
_start
;
Offset
?
_end
;
void
_updateGeometry
()
{
if
(
_start
==
null
||
_end
==
null
)
{
_geometry
.
value
=
_noSelection
;
return
;
}
final
Rect
renderObjectRect
=
Rect
.
fromLTWH
(
0
,
0
,
size
.
width
,
size
.
height
);
final
Rect
selectionRect
=
Rect
.
fromPoints
(
_start
!,
_end
!);
if
(
renderObjectRect
.
intersect
(
selectionRect
).
isEmpty
)
{
_geometry
.
value
=
_noSelection
;
}
else
{
final
Rect
selectionRect
=
_getSelectionHighlightRect
();
final
SelectionPoint
firstSelectionPoint
=
SelectionPoint
(
localPosition:
selectionRect
.
bottomLeft
,
lineHeight:
selectionRect
.
size
.
height
,
handleType:
TextSelectionHandleType
.
left
,
);
final
SelectionPoint
secondSelectionPoint
=
SelectionPoint
(
localPosition:
selectionRect
.
bottomRight
,
lineHeight:
selectionRect
.
size
.
height
,
handleType:
TextSelectionHandleType
.
right
,
);
final
bool
isReversed
;
if
(
_start
!.
dy
>
_end
!.
dy
)
{
isReversed
=
true
;
}
else
if
(
_start
!.
dy
<
_end
!.
dy
)
{
isReversed
=
false
;
}
else
{
isReversed
=
_start
!.
dx
>
_end
!.
dx
;
}
_geometry
.
value
=
SelectionGeometry
(
status:
SelectionStatus
.
uncollapsed
,
hasContent:
true
,
startSelectionPoint:
isReversed
?
secondSelectionPoint
:
firstSelectionPoint
,
endSelectionPoint:
isReversed
?
firstSelectionPoint
:
secondSelectionPoint
,
selectionRects:
<
Rect
>[
selectionRect
],
);
}
}
@override
SelectionResult
dispatchSelectionEvent
(
SelectionEvent
event
)
{
SelectionResult
result
=
SelectionResult
.
none
;
switch
(
event
.
type
)
{
case
SelectionEventType
.
startEdgeUpdate
:
case
SelectionEventType
.
endEdgeUpdate
:
final
Rect
renderObjectRect
=
Rect
.
fromLTWH
(
0
,
0
,
size
.
width
,
size
.
height
);
// Normalize offset in case it is out side of the rect.
final
Offset
point
=
globalToLocal
((
event
as
SelectionEdgeUpdateEvent
).
globalPosition
);
final
Offset
adjustedPoint
=
SelectionUtils
.
adjustDragOffset
(
renderObjectRect
,
point
);
if
(
event
.
type
==
SelectionEventType
.
startEdgeUpdate
)
{
_start
=
adjustedPoint
;
}
else
{
_end
=
adjustedPoint
;
}
result
=
SelectionUtils
.
getResultBasedOnRect
(
renderObjectRect
,
point
);
case
SelectionEventType
.
clear
:
_start
=
_end
=
null
;
case
SelectionEventType
.
selectAll
:
case
SelectionEventType
.
selectWord
:
case
SelectionEventType
.
selectParagraph
:
_start
=
Offset
.
zero
;
_end
=
Offset
.
infinite
;
case
SelectionEventType
.
granularlyExtendSelection
:
result
=
SelectionResult
.
end
;
final
GranularlyExtendSelectionEvent
extendSelectionEvent
=
event
as
GranularlyExtendSelectionEvent
;
// Initialize the offset it there is no ongoing selection.
if
(
_start
==
null
||
_end
==
null
)
{
if
(
extendSelectionEvent
.
forward
)
{
_start
=
_end
=
Offset
.
zero
;
}
else
{
_start
=
_end
=
Offset
.
infinite
;
}
}
// Move the corresponding selection edge.
final
Offset
newOffset
=
extendSelectionEvent
.
forward
?
Offset
.
infinite
:
Offset
.
zero
;
if
(
extendSelectionEvent
.
isEnd
)
{
if
(
newOffset
==
_end
)
{
result
=
extendSelectionEvent
.
forward
?
SelectionResult
.
next
:
SelectionResult
.
previous
;
}
_end
=
newOffset
;
}
else
{
if
(
newOffset
==
_start
)
{
result
=
extendSelectionEvent
.
forward
?
SelectionResult
.
next
:
SelectionResult
.
previous
;
}
_start
=
newOffset
;
}
case
SelectionEventType
.
directionallyExtendSelection
:
result
=
SelectionResult
.
end
;
final
DirectionallyExtendSelectionEvent
extendSelectionEvent
=
event
as
DirectionallyExtendSelectionEvent
;
// Convert to local coordinates.
final
double
horizontalBaseLine
=
globalToLocal
(
Offset
(
event
.
dx
,
0
)).
dx
;
final
Offset
newOffset
;
final
bool
forward
;
switch
(
extendSelectionEvent
.
direction
)
{
case
SelectionExtendDirection
.
backward
:
case
SelectionExtendDirection
.
previousLine
:
forward
=
false
;
// Initialize the offset it there is no ongoing selection.
if
(
_start
==
null
||
_end
==
null
)
{
_start
=
_end
=
Offset
.
infinite
;
}
// Move the corresponding selection edge.
if
(
extendSelectionEvent
.
direction
==
SelectionExtendDirection
.
previousLine
||
horizontalBaseLine
<
0
)
{
newOffset
=
Offset
.
zero
;
}
else
{
newOffset
=
Offset
.
infinite
;
}
case
SelectionExtendDirection
.
nextLine
:
case
SelectionExtendDirection
.
forward
:
forward
=
true
;
// Initialize the offset it there is no ongoing selection.
if
(
_start
==
null
||
_end
==
null
)
{
_start
=
_end
=
Offset
.
zero
;
}
// Move the corresponding selection edge.
if
(
extendSelectionEvent
.
direction
==
SelectionExtendDirection
.
nextLine
||
horizontalBaseLine
>
size
.
width
)
{
newOffset
=
Offset
.
infinite
;
}
else
{
newOffset
=
Offset
.
zero
;
}
}
if
(
extendSelectionEvent
.
isEnd
)
{
if
(
newOffset
==
_end
)
{
result
=
forward
?
SelectionResult
.
next
:
SelectionResult
.
previous
;
}
_end
=
newOffset
;
}
else
{
if
(
newOffset
==
_start
)
{
result
=
forward
?
SelectionResult
.
next
:
SelectionResult
.
previous
;
}
_start
=
newOffset
;
}
}
_updateGeometry
();
return
result
;
}
// This method is called when users want to copy selected content in this
// widget into clipboard.
@override
SelectedContent
?
getSelectedContent
()
{
return
value
.
hasSelection
?
SelectedContent
(
plainText:
selectionText
)
:
null
;
}
LayerLink
?
_startHandle
;
LayerLink
?
_endHandle
;
@override
void
pushHandleLayers
(
LayerLink
?
startHandle
,
LayerLink
?
endHandle
)
{
if
(
_startHandle
==
startHandle
&&
_endHandle
==
endHandle
)
{
return
;
}
_startHandle
=
startHandle
;
_endHandle
=
endHandle
;
markNeedsPaint
();
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
super
.
paint
(
context
,
offset
);
if
(!
_geometry
.
value
.
hasSelection
)
{
return
;
}
// Draw the selection highlight.
final
Paint
selectionPaint
=
Paint
()
..
style
=
PaintingStyle
.
fill
..
color
=
_selectionColor
;
context
.
canvas
.
drawRect
(
_getSelectionHighlightRect
().
shift
(
offset
),
selectionPaint
);
// Push the layer links if any.
if
(
_startHandle
!=
null
)
{
context
.
pushLayer
(
LeaderLayer
(
link:
_startHandle
!,
offset:
offset
+
value
.
startSelectionPoint
!.
localPosition
,
),
(
PaintingContext
context
,
Offset
offset
)
{},
Offset
.
zero
,
);
}
if
(
_endHandle
!=
null
)
{
context
.
pushLayer
(
LeaderLayer
(
link:
_endHandle
!,
offset:
offset
+
value
.
endSelectionPoint
!.
localPosition
,
),
(
PaintingContext
context
,
Offset
offset
)
{},
Offset
.
zero
,
);
}
}
@override
void
dispose
()
{
_geometry
.
dispose
();
super
.
dispose
();
}
}
...
...
gpt_markdown/example/pubspec.lock
View file @
c3dc6e6
...
...
@@ -126,7 +126,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.1.1
0
"
version: "0.1.1
1
"
http:
dependency: transitive
description:
...
...
@@ -373,5 +373,5 @@ packages:
source: hosted
version: "6.5.0"
sdks:
dart: ">=3.
3
.0 <4.0.0"
dart: ">=3.
5
.0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"
...
...
gpt_markdown/example/pubspec.yaml
View file @
c3dc6e6
...
...
@@ -5,7 +5,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version
:
1.0.0+1
environment
:
sdk
:
'
>=
2.18.6
<4.0.0'
sdk
:
'
>=
3.5.0
<4.0.0'
dependencies
:
flutter
:
sdk
:
flutter
...
...
gpt_markdown/lib/markdown_component.dart
View file @
c3dc6e6
...
...
@@ -7,6 +7,7 @@ import 'package:gpt_markdown/custom_widgets/custom_error_image.dart';
import
'package:gpt_markdown/custom_widgets/custom_rb_cb.dart'
;
import
'package:gpt_markdown/custom_widgets/markdow_config.dart'
;
import
'package:gpt_markdown/custom_widgets/unordered_ordered_list.dart'
;
import
'package:gpt_markdown/theme.dart'
;
import
'md_widget.dart'
;
/// Markdown components
...
...
@@ -413,14 +414,14 @@ class HighlightedText extends InlineMd {
style:
config
.
style
?.
copyWith
(
fontWeight:
FontWeight
.
bold
,
background:
Paint
()
..
color
=
Theme
.
of
(
context
).
colorScheme
.
onInverseSurface
..
color
=
GptMarkdownTheme
.
of
(
context
).
highlightColor
..
strokeCap
=
StrokeCap
.
round
..
strokeJoin
=
StrokeJoin
.
round
,
)
??
TextStyle
(
fontWeight:
FontWeight
.
bold
,
background:
Paint
()
..
color
=
Theme
.
of
(
context
).
colorScheme
.
surfaceContainerHighest
..
color
=
GptMarkdownTheme
.
of
(
context
).
highlightColor
..
strokeCap
=
StrokeCap
.
round
..
strokeJoin
=
StrokeJoin
.
round
,
),
...
...
gpt_markdown/lib/theme.dart
0 → 100644
View file @
c3dc6e6
import
'package:flutter/material.dart'
;
/// Theme defined for `TexMarkdown` widget
class
GptMarkdownThemeData
extends
ThemeExtension
<
GptMarkdownThemeData
>
{
GptMarkdownThemeData
({
required
this
.
highlightColor
,
});
/// Define default attributes.
factory
GptMarkdownThemeData
.
from
(
BuildContext
context
)
{
return
GptMarkdownThemeData
(
highlightColor:
Theme
.
of
(
context
).
colorScheme
.
onInverseSurface
,
);
}
Color
highlightColor
;
@override
GptMarkdownThemeData
copyWith
({
Color
?
highlightColor
})
{
return
GptMarkdownThemeData
(
highlightColor:
highlightColor
??
this
.
highlightColor
,
);
}
@override
GptMarkdownThemeData
lerp
(
GptMarkdownThemeData
?
other
,
double
t
)
{
if
(
other
==
null
)
{
return
this
;
}
return
GptMarkdownThemeData
(
highlightColor:
Color
.
lerp
(
highlightColor
,
other
.
highlightColor
,
t
)
??
highlightColor
,
);
}
}
/// Wrap a `Widget` with `GptMarkdownTheme` to provide `GptMarkdownThemeData` in your intiar app.
class
GptMarkdownTheme
extends
InheritedWidget
{
const
GptMarkdownTheme
({
super
.
key
,
required
this
.
gptThemeData
,
required
super
.
child
,
});
final
GptMarkdownThemeData
gptThemeData
;
static
GptMarkdownThemeData
of
(
BuildContext
context
)
{
final
provider
=
context
.
dependOnInheritedWidgetOfExactType
<
GptMarkdownTheme
>();
if
(
provider
!=
null
)
{
return
provider
.
gptThemeData
;
}
final
themeData
=
Theme
.
of
(
context
).
extension
<
GptMarkdownThemeData
>();
if
(
themeData
!=
null
)
{
return
themeData
;
}
return
GptMarkdownThemeData
.
from
(
context
);
}
@override
bool
updateShouldNotify
(
GptMarkdownTheme
oldWidget
)
{
return
gptThemeData
!=
oldWidget
.
gptThemeData
;
}
}
...
...
gpt_markdown/pubspec.yaml
View file @
c3dc6e6
name
:
gpt_markdown
description
:
"
The
purpose
of
this
package
is
to
render
the
response
of
ChatGPT
into
a
Flutter
app."
version
:
0.1.1
0
version
:
0.1.1
1
homepage
:
https://github.com/saminsohag/flutter_packages/tree/main/gpt_markdown
environment
:
...
...
Please
register
or
login
to post a comment