parent
							
								
									214b06cac8
								
							
						
					
					
						commit
						f794515cc7
					
				| @ -0,0 +1,15 @@ | ||||
| .DS_Store | ||||
| .dart_tool/ | ||||
| 
 | ||||
| .packages | ||||
| .flutter-plugins | ||||
| .pub/ | ||||
| 
 | ||||
| .idea/ | ||||
| *.iml | ||||
| *.lock | ||||
| 
 | ||||
| 
 | ||||
| build/ | ||||
| ios/ | ||||
| android/ | ||||
| @ -0,0 +1,5 @@ | ||||
| ## 1.0.2 | ||||
| * Fix icon not display. | ||||
| ## 1.0.1 | ||||
| * Change directory structure. | ||||
| ## 1.0.0 | ||||
| @ -0,0 +1,339 @@ | ||||
|                     GNU GENERAL PUBLIC LICENSE | ||||
|                        Version 2, June 1991 | ||||
| 
 | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc., | ||||
|  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
| 
 | ||||
|                             Preamble | ||||
| 
 | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| License is intended to guarantee your freedom to share and change free | ||||
| software--to make sure the software is free for all its users.  This | ||||
| General Public License applies to most of the Free Software | ||||
| Foundation's software and to any other program whose authors commit to | ||||
| using it.  (Some other Free Software Foundation software is covered by | ||||
| the GNU Lesser General Public License instead.)  You can apply it to | ||||
| your programs, too. | ||||
| 
 | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| this service if you wish), that you receive source code or can get it | ||||
| if you want it, that you can change the software or use pieces of it | ||||
| in new free programs; and that you know you can do these things. | ||||
| 
 | ||||
|   To protect your rights, we need to make restrictions that forbid | ||||
| anyone to deny you these rights or to ask you to surrender the rights. | ||||
| These restrictions translate to certain responsibilities for you if you | ||||
| distribute copies of the software, or if you modify it. | ||||
| 
 | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must give the recipients all the rights that | ||||
| you have.  You must make sure that they, too, receive or can get the | ||||
| source code.  And you must show them these terms so they know their | ||||
| rights. | ||||
| 
 | ||||
|   We protect your rights with two steps: (1) copyright the software, and | ||||
| (2) offer you this license which gives you legal permission to copy, | ||||
| distribute and/or modify the software. | ||||
| 
 | ||||
|   Also, for each author's protection and ours, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| software.  If the software is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original, so | ||||
| that any problems introduced by others will not reflect on the original | ||||
| authors' reputations. | ||||
| 
 | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that redistributors of a free | ||||
| program will individually obtain patent licenses, in effect making the | ||||
| program proprietary.  To prevent this, we have made it clear that any | ||||
| patent must be licensed for everyone's free use or not licensed at all. | ||||
| 
 | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
| 
 | ||||
|                     GNU GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
| 
 | ||||
|   0. This License applies to any program or other work which contains | ||||
| a notice placed by the copyright holder saying it may be distributed | ||||
| under the terms of this General Public License.  The "Program", below, | ||||
| refers to any such program or work, and a "work based on the Program" | ||||
| means either the Program or any derivative work under copyright law: | ||||
| that is to say, a work containing the Program or a portion of it, | ||||
| either verbatim or with modifications and/or translated into another | ||||
| language.  (Hereinafter, translation is included without limitation in | ||||
| the term "modification".)  Each licensee is addressed as "you". | ||||
| 
 | ||||
| Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running the Program is not restricted, and the output from the Program | ||||
| is covered only if its contents constitute a work based on the | ||||
| Program (independent of having been made by running the Program). | ||||
| Whether that is true depends on what the Program does. | ||||
| 
 | ||||
|   1. You may copy and distribute verbatim copies of the Program's | ||||
| source code as you receive it, in any medium, provided that you | ||||
| conspicuously and appropriately publish on each copy an appropriate | ||||
| copyright notice and disclaimer of warranty; keep intact all the | ||||
| notices that refer to this License and to the absence of any warranty; | ||||
| and give any other recipients of the Program a copy of this License | ||||
| along with the Program. | ||||
| 
 | ||||
| You may charge a fee for the physical act of transferring a copy, and | ||||
| you may at your option offer warranty protection in exchange for a fee. | ||||
| 
 | ||||
|   2. You may modify your copy or copies of the Program or any portion | ||||
| of it, thus forming a work based on the Program, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
| 
 | ||||
|     a) You must cause the modified files to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
| 
 | ||||
|     b) You must cause any work that you distribute or publish, that in | ||||
|     whole or in part contains or is derived from the Program or any | ||||
|     part thereof, to be licensed as a whole at no charge to all third | ||||
|     parties under the terms of this License. | ||||
| 
 | ||||
|     c) If the modified program normally reads commands interactively | ||||
|     when run, you must cause it, when started running for such | ||||
|     interactive use in the most ordinary way, to print or display an | ||||
|     announcement including an appropriate copyright notice and a | ||||
|     notice that there is no warranty (or else, saying that you provide | ||||
|     a warranty) and that users may redistribute the program under | ||||
|     these conditions, and telling the user how to view a copy of this | ||||
|     License.  (Exception: if the Program itself is interactive but | ||||
|     does not normally print such an announcement, your work based on | ||||
|     the Program is not required to print an announcement.) | ||||
| 
 | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Program, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Program, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote it. | ||||
| 
 | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Program. | ||||
| 
 | ||||
| In addition, mere aggregation of another work not based on the Program | ||||
| with the Program (or with a work based on the Program) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
| 
 | ||||
|   3. You may copy and distribute the Program (or a work based on it, | ||||
| under Section 2) in object code or executable form under the terms of | ||||
| Sections 1 and 2 above provided that you also do one of the following: | ||||
| 
 | ||||
|     a) Accompany it with the complete corresponding machine-readable | ||||
|     source code, which must be distributed under the terms of Sections | ||||
|     1 and 2 above on a medium customarily used for software interchange; or, | ||||
| 
 | ||||
|     b) Accompany it with a written offer, valid for at least three | ||||
|     years, to give any third party, for a charge no more than your | ||||
|     cost of physically performing source distribution, a complete | ||||
|     machine-readable copy of the corresponding source code, to be | ||||
|     distributed under the terms of Sections 1 and 2 above on a medium | ||||
|     customarily used for software interchange; or, | ||||
| 
 | ||||
|     c) Accompany it with the information you received as to the offer | ||||
|     to distribute corresponding source code.  (This alternative is | ||||
|     allowed only for noncommercial distribution and only if you | ||||
|     received the program in object code or executable form with such | ||||
|     an offer, in accord with Subsection b above.) | ||||
| 
 | ||||
| The source code for a work means the preferred form of the work for | ||||
| making modifications to it.  For an executable work, complete source | ||||
| code means all the source code for all modules it contains, plus any | ||||
| associated interface definition files, plus the scripts used to | ||||
| control compilation and installation of the executable.  However, as a | ||||
| special exception, the source code distributed need not include | ||||
| anything that is normally distributed (in either source or binary | ||||
| form) with the major components (compiler, kernel, and so on) of the | ||||
| operating system on which the executable runs, unless that component | ||||
| itself accompanies the executable. | ||||
| 
 | ||||
| If distribution of executable or object code is made by offering | ||||
| access to copy from a designated place, then offering equivalent | ||||
| access to copy the source code from the same place counts as | ||||
| distribution of the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
| 
 | ||||
|   4. You may not copy, modify, sublicense, or distribute the Program | ||||
| except as expressly provided under this License.  Any attempt | ||||
| otherwise to copy, modify, sublicense or distribute the Program is | ||||
| void, and will automatically terminate your rights under this License. | ||||
| However, parties who have received copies, or rights, from you under | ||||
| this License will not have their licenses terminated so long as such | ||||
| parties remain in full compliance. | ||||
| 
 | ||||
|   5. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Program or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Program (or any work based on the | ||||
| Program), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Program or works based on it. | ||||
| 
 | ||||
|   6. Each time you redistribute the Program (or any work based on the | ||||
| Program), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute or modify the Program subject to | ||||
| these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties to | ||||
| this License. | ||||
| 
 | ||||
|   7. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Program at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Program by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Program. | ||||
| 
 | ||||
| If any portion of this section is held invalid or unenforceable under | ||||
| any particular circumstance, the balance of the section is intended to | ||||
| apply and the section as a whole is intended to apply in other | ||||
| circumstances. | ||||
| 
 | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system, which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
| 
 | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
| 
 | ||||
|   8. If the distribution and/or use of the Program is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Program under this License | ||||
| may add an explicit geographical distribution limitation excluding | ||||
| those countries, so that distribution is permitted only in or among | ||||
| countries not thus excluded.  In such case, this License incorporates | ||||
| the limitation as if written in the body of this License. | ||||
| 
 | ||||
|   9. The Free Software Foundation may publish revised and/or new versions | ||||
| of the General Public License from time to time.  Such new versions will | ||||
| be similar in spirit to the present version, but may differ in detail to | ||||
| address new problems or concerns. | ||||
| 
 | ||||
| Each version is given a distinguishing version number.  If the Program | ||||
| specifies a version number of this License which applies to it and "any | ||||
| later version", you have the option of following the terms and conditions | ||||
| either of that version or of any later version published by the Free | ||||
| Software Foundation.  If the Program does not specify a version number of | ||||
| this License, you may choose any version ever published by the Free Software | ||||
| Foundation. | ||||
| 
 | ||||
|   10. If you wish to incorporate parts of the Program into other free | ||||
| programs whose distribution conditions are different, write to the author | ||||
| to ask for permission.  For software which is copyrighted by the Free | ||||
| Software Foundation, write to the Free Software Foundation; we sometimes | ||||
| make exceptions for this.  Our decision will be guided by the two goals | ||||
| of preserving the free status of all derivatives of our free software and | ||||
| of promoting the sharing and reuse of software generally. | ||||
| 
 | ||||
|                             NO WARRANTY | ||||
| 
 | ||||
|   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN | ||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||
| REPAIR OR CORRECTION. | ||||
| 
 | ||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGES. | ||||
| 
 | ||||
|                      END OF TERMS AND CONDITIONS | ||||
| 
 | ||||
|             How to Apply These Terms to Your New Programs | ||||
| 
 | ||||
|   If you develop a new program, and you want it to be of the greatest | ||||
| possible use to the public, the best way to achieve this is to make it | ||||
| free software which everyone can redistribute and change under these terms. | ||||
| 
 | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
| 
 | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License along | ||||
|     with this program; if not, write to the Free Software Foundation, Inc., | ||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
| 
 | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
| 
 | ||||
| If the program is interactive, make it output a short notice like this | ||||
| when it starts in an interactive mode: | ||||
| 
 | ||||
|     Gnomovision version 69, Copyright (C) year name of author | ||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||
|     This is free software, and you are welcome to redistribute it | ||||
|     under certain conditions; type `show c' for details. | ||||
| 
 | ||||
| The hypothetical commands `show w' and `show c' should show the appropriate | ||||
| parts of the General Public License.  Of course, the commands you use may | ||||
| be called something other than `show w' and `show c'; they could even be | ||||
| mouse-clicks or menu items--whatever suits your program. | ||||
| 
 | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the program, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
| 
 | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||
| 
 | ||||
|   <signature of Ty Coon>, 1 April 1989 | ||||
|   Ty Coon, President of Vice | ||||
| 
 | ||||
| This General Public License does not permit incorporating your program into | ||||
| proprietary programs.  If your program is a subroutine library, you may | ||||
| consider it more useful to permit linking proprietary applications with the | ||||
| library.  If this is what you want to do, use the GNU Lesser General | ||||
| Public License instead of this License. | ||||
| @ -0,0 +1,23 @@ | ||||
| # markdown_editor | ||||
| 
 | ||||
| Simple and easy to implement your markdown editor, it uses its own parser. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| If you only need to render, you can refer to [https://github.com/xia-weiyang/markdown_core](https://github.com/xia-weiyang/markdown_core) | ||||
| 
 | ||||
| ``` dart | ||||
| MarkdownEditor( | ||||
|       initText: 'initText', | ||||
|       initTitle: 'initText', | ||||
|       onTapLink: (link){ | ||||
|         print('点击了链接 $link'); | ||||
|       }, | ||||
|       imageWidget: (imageUrl) { | ||||
|         return // Your image widget ; | ||||
|       }, | ||||
|       imageSelect: (){ // Click image select btn | ||||
|         return // selected image link; | ||||
|       }, | ||||
| ) | ||||
| ``` | ||||
| @ -0,0 +1,539 @@ | ||||
| /* Logo 字体 */ | ||||
| @font-face { | ||||
|   font-family: "iconfont logo"; | ||||
|   src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); | ||||
|   src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), | ||||
|     url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), | ||||
|     url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), | ||||
|     url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); | ||||
| } | ||||
| 
 | ||||
| .logo { | ||||
|   font-family: "iconfont logo"; | ||||
|   font-size: 160px; | ||||
|   font-style: normal; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
| } | ||||
| 
 | ||||
| /* tabs */ | ||||
| .nav-tabs { | ||||
|   position: relative; | ||||
| } | ||||
| 
 | ||||
| .nav-tabs .nav-more { | ||||
|   position: absolute; | ||||
|   right: 0; | ||||
|   bottom: 0; | ||||
|   height: 42px; | ||||
|   line-height: 42px; | ||||
|   color: #666; | ||||
| } | ||||
| 
 | ||||
| #tabs { | ||||
|   border-bottom: 1px solid #eee; | ||||
| } | ||||
| 
 | ||||
| #tabs li { | ||||
|   cursor: pointer; | ||||
|   width: 100px; | ||||
|   height: 40px; | ||||
|   line-height: 40px; | ||||
|   text-align: center; | ||||
|   font-size: 16px; | ||||
|   border-bottom: 2px solid transparent; | ||||
|   position: relative; | ||||
|   z-index: 1; | ||||
|   margin-bottom: -1px; | ||||
|   color: #666; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #tabs .active { | ||||
|   border-bottom-color: #f00; | ||||
|   color: #222; | ||||
| } | ||||
| 
 | ||||
| .tab-container .content { | ||||
|   display: none; | ||||
| } | ||||
| 
 | ||||
| /* 页面布局 */ | ||||
| .main { | ||||
|   padding: 30px 100px; | ||||
|   width: 960px; | ||||
|   margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| .main .logo { | ||||
|   color: #333; | ||||
|   text-align: left; | ||||
|   margin-bottom: 30px; | ||||
|   line-height: 1; | ||||
|   height: 110px; | ||||
|   margin-top: -50px; | ||||
|   overflow: hidden; | ||||
|   *zoom: 1; | ||||
| } | ||||
| 
 | ||||
| .main .logo a { | ||||
|   font-size: 160px; | ||||
|   color: #333; | ||||
| } | ||||
| 
 | ||||
| .helps { | ||||
|   margin-top: 40px; | ||||
| } | ||||
| 
 | ||||
| .helps pre { | ||||
|   padding: 20px; | ||||
|   margin: 10px 0; | ||||
|   border: solid 1px #e7e1cd; | ||||
|   background-color: #fffdef; | ||||
|   overflow: auto; | ||||
| } | ||||
| 
 | ||||
| .icon_lists { | ||||
|   width: 100% !important; | ||||
|   overflow: hidden; | ||||
|   *zoom: 1; | ||||
| } | ||||
| 
 | ||||
| .icon_lists li { | ||||
|   width: 100px; | ||||
|   margin-bottom: 10px; | ||||
|   margin-right: 20px; | ||||
|   text-align: center; | ||||
|   list-style: none !important; | ||||
|   cursor: default; | ||||
| } | ||||
| 
 | ||||
| .icon_lists li .code-name { | ||||
|   line-height: 1.2; | ||||
| } | ||||
| 
 | ||||
| .icon_lists .icon { | ||||
|   display: block; | ||||
|   height: 100px; | ||||
|   line-height: 100px; | ||||
|   font-size: 42px; | ||||
|   margin: 10px auto; | ||||
|   color: #333; | ||||
|   -webkit-transition: font-size 0.25s linear, width 0.25s linear; | ||||
|   -moz-transition: font-size 0.25s linear, width 0.25s linear; | ||||
|   transition: font-size 0.25s linear, width 0.25s linear; | ||||
| } | ||||
| 
 | ||||
| .icon_lists .icon:hover { | ||||
|   font-size: 100px; | ||||
| } | ||||
| 
 | ||||
| .icon_lists .svg-icon { | ||||
|   /* 通过设置 font-size 来改变图标大小 */ | ||||
|   width: 1em; | ||||
|   /* 图标和文字相邻时,垂直对齐 */ | ||||
|   vertical-align: -0.15em; | ||||
|   /* 通过设置 color 来改变 SVG 的颜色/fill */ | ||||
|   fill: currentColor; | ||||
|   /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 | ||||
|       normalize.css 中也包含这行 */ | ||||
|   overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| .icon_lists li .name, | ||||
| .icon_lists li .code-name { | ||||
|   color: #666; | ||||
| } | ||||
| 
 | ||||
| /* markdown 样式 */ | ||||
| .markdown { | ||||
|   color: #666; | ||||
|   font-size: 14px; | ||||
|   line-height: 1.8; | ||||
| } | ||||
| 
 | ||||
| .highlight { | ||||
|   line-height: 1.5; | ||||
| } | ||||
| 
 | ||||
| .markdown img { | ||||
|   vertical-align: middle; | ||||
|   max-width: 100%; | ||||
| } | ||||
| 
 | ||||
| .markdown h1 { | ||||
|   color: #404040; | ||||
|   font-weight: 500; | ||||
|   line-height: 40px; | ||||
|   margin-bottom: 24px; | ||||
| } | ||||
| 
 | ||||
| .markdown h2, | ||||
| .markdown h3, | ||||
| .markdown h4, | ||||
| .markdown h5, | ||||
| .markdown h6 { | ||||
|   color: #404040; | ||||
|   margin: 1.6em 0 0.6em 0; | ||||
|   font-weight: 500; | ||||
|   clear: both; | ||||
| } | ||||
| 
 | ||||
| .markdown h1 { | ||||
|   font-size: 28px; | ||||
| } | ||||
| 
 | ||||
| .markdown h2 { | ||||
|   font-size: 22px; | ||||
| } | ||||
| 
 | ||||
| .markdown h3 { | ||||
|   font-size: 16px; | ||||
| } | ||||
| 
 | ||||
| .markdown h4 { | ||||
|   font-size: 14px; | ||||
| } | ||||
| 
 | ||||
| .markdown h5 { | ||||
|   font-size: 12px; | ||||
| } | ||||
| 
 | ||||
| .markdown h6 { | ||||
|   font-size: 12px; | ||||
| } | ||||
| 
 | ||||
| .markdown hr { | ||||
|   height: 1px; | ||||
|   border: 0; | ||||
|   background: #e9e9e9; | ||||
|   margin: 16px 0; | ||||
|   clear: both; | ||||
| } | ||||
| 
 | ||||
| .markdown p { | ||||
|   margin: 1em 0; | ||||
| } | ||||
| 
 | ||||
| .markdown>p, | ||||
| .markdown>blockquote, | ||||
| .markdown>.highlight, | ||||
| .markdown>ol, | ||||
| .markdown>ul { | ||||
|   width: 80%; | ||||
| } | ||||
| 
 | ||||
| .markdown ul>li { | ||||
|   list-style: circle; | ||||
| } | ||||
| 
 | ||||
| .markdown>ul li, | ||||
| .markdown blockquote ul>li { | ||||
|   margin-left: 20px; | ||||
|   padding-left: 4px; | ||||
| } | ||||
| 
 | ||||
| .markdown>ul li p, | ||||
| .markdown>ol li p { | ||||
|   margin: 0.6em 0; | ||||
| } | ||||
| 
 | ||||
| .markdown ol>li { | ||||
|   list-style: decimal; | ||||
| } | ||||
| 
 | ||||
| .markdown>ol li, | ||||
| .markdown blockquote ol>li { | ||||
|   margin-left: 20px; | ||||
|   padding-left: 4px; | ||||
| } | ||||
| 
 | ||||
| .markdown code { | ||||
|   margin: 0 3px; | ||||
|   padding: 0 5px; | ||||
|   background: #eee; | ||||
|   border-radius: 3px; | ||||
| } | ||||
| 
 | ||||
| .markdown strong, | ||||
| .markdown b { | ||||
|   font-weight: 600; | ||||
| } | ||||
| 
 | ||||
| .markdown>table { | ||||
|   border-collapse: collapse; | ||||
|   border-spacing: 0px; | ||||
|   empty-cells: show; | ||||
|   border: 1px solid #e9e9e9; | ||||
|   width: 95%; | ||||
|   margin-bottom: 24px; | ||||
| } | ||||
| 
 | ||||
| .markdown>table th { | ||||
|   white-space: nowrap; | ||||
|   color: #333; | ||||
|   font-weight: 600; | ||||
| } | ||||
| 
 | ||||
| .markdown>table th, | ||||
| .markdown>table td { | ||||
|   border: 1px solid #e9e9e9; | ||||
|   padding: 8px 16px; | ||||
|   text-align: left; | ||||
| } | ||||
| 
 | ||||
| .markdown>table th { | ||||
|   background: #F7F7F7; | ||||
| } | ||||
| 
 | ||||
| .markdown blockquote { | ||||
|   font-size: 90%; | ||||
|   color: #999; | ||||
|   border-left: 4px solid #e9e9e9; | ||||
|   padding-left: 0.8em; | ||||
|   margin: 1em 0; | ||||
| } | ||||
| 
 | ||||
| .markdown blockquote p { | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| .markdown .anchor { | ||||
|   opacity: 0; | ||||
|   transition: opacity 0.3s ease; | ||||
|   margin-left: 8px; | ||||
| } | ||||
| 
 | ||||
| .markdown .waiting { | ||||
|   color: #ccc; | ||||
| } | ||||
| 
 | ||||
| .markdown h1:hover .anchor, | ||||
| .markdown h2:hover .anchor, | ||||
| .markdown h3:hover .anchor, | ||||
| .markdown h4:hover .anchor, | ||||
| .markdown h5:hover .anchor, | ||||
| .markdown h6:hover .anchor { | ||||
|   opacity: 1; | ||||
|   display: inline-block; | ||||
| } | ||||
| 
 | ||||
| .markdown>br, | ||||
| .markdown>p>br { | ||||
|   clear: both; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| .hljs { | ||||
|   display: block; | ||||
|   background: white; | ||||
|   padding: 0.5em; | ||||
|   color: #333333; | ||||
|   overflow-x: auto; | ||||
| } | ||||
| 
 | ||||
| .hljs-comment, | ||||
| .hljs-meta { | ||||
|   color: #969896; | ||||
| } | ||||
| 
 | ||||
| .hljs-string, | ||||
| .hljs-variable, | ||||
| .hljs-template-variable, | ||||
| .hljs-strong, | ||||
| .hljs-emphasis, | ||||
| .hljs-quote { | ||||
|   color: #df5000; | ||||
| } | ||||
| 
 | ||||
| .hljs-keyword, | ||||
| .hljs-selector-tag, | ||||
| .hljs-type { | ||||
|   color: #a71d5d; | ||||
| } | ||||
| 
 | ||||
| .hljs-literal, | ||||
| .hljs-symbol, | ||||
| .hljs-bullet, | ||||
| .hljs-attribute { | ||||
|   color: #0086b3; | ||||
| } | ||||
| 
 | ||||
| .hljs-section, | ||||
| .hljs-name { | ||||
|   color: #63a35c; | ||||
| } | ||||
| 
 | ||||
| .hljs-tag { | ||||
|   color: #333333; | ||||
| } | ||||
| 
 | ||||
| .hljs-title, | ||||
| .hljs-attr, | ||||
| .hljs-selector-id, | ||||
| .hljs-selector-class, | ||||
| .hljs-selector-attr, | ||||
| .hljs-selector-pseudo { | ||||
|   color: #795da3; | ||||
| } | ||||
| 
 | ||||
| .hljs-addition { | ||||
|   color: #55a532; | ||||
|   background-color: #eaffea; | ||||
| } | ||||
| 
 | ||||
| .hljs-deletion { | ||||
|   color: #bd2c00; | ||||
|   background-color: #ffecec; | ||||
| } | ||||
| 
 | ||||
| .hljs-link { | ||||
|   text-decoration: underline; | ||||
| } | ||||
| 
 | ||||
| /* 代码高亮 */ | ||||
| /* PrismJS 1.15.0 | ||||
| https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ | ||||
| /** | ||||
|  * prism.js default theme for JavaScript, CSS and HTML | ||||
|  * Based on dabblet (http://dabblet.com) | ||||
|  * @author Lea Verou | ||||
|  */ | ||||
| code[class*="language-"], | ||||
| pre[class*="language-"] { | ||||
|   color: black; | ||||
|   background: none; | ||||
|   text-shadow: 0 1px white; | ||||
|   font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; | ||||
|   text-align: left; | ||||
|   white-space: pre; | ||||
|   word-spacing: normal; | ||||
|   word-break: normal; | ||||
|   word-wrap: normal; | ||||
|   line-height: 1.5; | ||||
| 
 | ||||
|   -moz-tab-size: 4; | ||||
|   -o-tab-size: 4; | ||||
|   tab-size: 4; | ||||
| 
 | ||||
|   -webkit-hyphens: none; | ||||
|   -moz-hyphens: none; | ||||
|   -ms-hyphens: none; | ||||
|   hyphens: none; | ||||
| } | ||||
| 
 | ||||
| pre[class*="language-"]::-moz-selection, | ||||
| pre[class*="language-"] ::-moz-selection, | ||||
| code[class*="language-"]::-moz-selection, | ||||
| code[class*="language-"] ::-moz-selection { | ||||
|   text-shadow: none; | ||||
|   background: #b3d4fc; | ||||
| } | ||||
| 
 | ||||
| pre[class*="language-"]::selection, | ||||
| pre[class*="language-"] ::selection, | ||||
| code[class*="language-"]::selection, | ||||
| code[class*="language-"] ::selection { | ||||
|   text-shadow: none; | ||||
|   background: #b3d4fc; | ||||
| } | ||||
| 
 | ||||
| @media print { | ||||
| 
 | ||||
|   code[class*="language-"], | ||||
|   pre[class*="language-"] { | ||||
|     text-shadow: none; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* Code blocks */ | ||||
| pre[class*="language-"] { | ||||
|   padding: 1em; | ||||
|   margin: .5em 0; | ||||
|   overflow: auto; | ||||
| } | ||||
| 
 | ||||
| :not(pre)>code[class*="language-"], | ||||
| pre[class*="language-"] { | ||||
|   background: #f5f2f0; | ||||
| } | ||||
| 
 | ||||
| /* Inline code */ | ||||
| :not(pre)>code[class*="language-"] { | ||||
|   padding: .1em; | ||||
|   border-radius: .3em; | ||||
|   white-space: normal; | ||||
| } | ||||
| 
 | ||||
| .token.comment, | ||||
| .token.prolog, | ||||
| .token.doctype, | ||||
| .token.cdata { | ||||
|   color: slategray; | ||||
| } | ||||
| 
 | ||||
| .token.punctuation { | ||||
|   color: #999; | ||||
| } | ||||
| 
 | ||||
| .namespace { | ||||
|   opacity: .7; | ||||
| } | ||||
| 
 | ||||
| .token.property, | ||||
| .token.tag, | ||||
| .token.boolean, | ||||
| .token.number, | ||||
| .token.constant, | ||||
| .token.symbol, | ||||
| .token.deleted { | ||||
|   color: #905; | ||||
| } | ||||
| 
 | ||||
| .token.selector, | ||||
| .token.attr-name, | ||||
| .token.string, | ||||
| .token.char, | ||||
| .token.builtin, | ||||
| .token.inserted { | ||||
|   color: #690; | ||||
| } | ||||
| 
 | ||||
| .token.operator, | ||||
| .token.entity, | ||||
| .token.url, | ||||
| .language-css .token.string, | ||||
| .style .token.string { | ||||
|   color: #9a6e3a; | ||||
|   background: hsla(0, 0%, 100%, .5); | ||||
| } | ||||
| 
 | ||||
| .token.atrule, | ||||
| .token.attr-value, | ||||
| .token.keyword { | ||||
|   color: #07a; | ||||
| } | ||||
| 
 | ||||
| .token.function, | ||||
| .token.class-name { | ||||
|   color: #DD4A68; | ||||
| } | ||||
| 
 | ||||
| .token.regex, | ||||
| .token.important, | ||||
| .token.variable { | ||||
|   color: #e90; | ||||
| } | ||||
| 
 | ||||
| .token.important, | ||||
| .token.bold { | ||||
|   font-weight: bold; | ||||
| } | ||||
| 
 | ||||
| .token.italic { | ||||
|   font-style: italic; | ||||
| } | ||||
| 
 | ||||
| .token.entity { | ||||
|   cursor: help; | ||||
| } | ||||
| @ -0,0 +1,113 @@ | ||||
| @font-face {font-family: "iconfont"; | ||||
|   src: url('iconfont.eot?t=1556453824121'); /* IE9 */ | ||||
|   src: url('iconfont.eot?t=1556453824121#iefix') format('embedded-opentype'), /* IE6-IE8 */ | ||||
|   url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), | ||||
|   url('iconfont.woff?t=1556453824121') format('woff'), | ||||
|   url('iconfont.ttf?t=1556453824121') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ | ||||
|   url('iconfont.svg?t=1556453824121#iconfont') format('svg'); /* iOS 4.1- */ | ||||
| } | ||||
| 
 | ||||
| .iconfont { | ||||
|   font-family: "iconfont" !important; | ||||
|   font-size: 16px; | ||||
|   font-style: normal; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
| } | ||||
| 
 | ||||
| .icon-format-bold:before { | ||||
|   content: "\e757"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-color-text:before { | ||||
|   content: "\e758"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-header-:before { | ||||
|   content: "\e75b"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-header-1:before { | ||||
|   content: "\e75c"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-header-2:before { | ||||
|   content: "\e75d"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-header-3:before { | ||||
|   content: "\e75e"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-header-4:before { | ||||
|   content: "\e75f"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-header-5:before { | ||||
|   content: "\e760"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-italic:before { | ||||
|   content: "\e762"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-list-bulleted:before { | ||||
|   content: "\e764"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-list-numbers:before { | ||||
|   content: "\e765"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-quote:before { | ||||
|   content: "\e768"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-size:before { | ||||
|   content: "\e769"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-strikethrough:before { | ||||
|   content: "\e76a"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-title:before { | ||||
|   content: "\e76f"; | ||||
| } | ||||
| 
 | ||||
| .icon-format-underline:before { | ||||
|   content: "\e770"; | ||||
| } | ||||
| 
 | ||||
| .icon-image:before { | ||||
|   content: "\e7ac"; | ||||
| } | ||||
| 
 | ||||
| .icon-link-variant:before { | ||||
|   content: "\e7d8"; | ||||
| } | ||||
| 
 | ||||
| .icon-redo:before { | ||||
|   content: "\e873"; | ||||
| } | ||||
| 
 | ||||
| .icon-redo-variant:before { | ||||
|   content: "\e874"; | ||||
| } | ||||
| 
 | ||||
| .icon-timer:before { | ||||
|   content: "\e8eb"; | ||||
| } | ||||
| 
 | ||||
| .icon-undo-variant:before { | ||||
|   content: "\e907"; | ||||
| } | ||||
| 
 | ||||
| .icon-undo:before { | ||||
|   content: "\e908"; | ||||
| } | ||||
| 
 | ||||
| .icon-weather-cloudy:before { | ||||
|   content: "\e92d"; | ||||
| } | ||||
| 
 | ||||
											
												Binary file not shown.
											
										
									
								
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								| After Width: | Height: | Size: 12 KiB | 
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,29 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| class CustomizePhysics extends ScrollPhysics { | ||||
|   const CustomizePhysics({ | ||||
|     ScrollPhysics? parent, | ||||
|   }) : super(parent: parent); | ||||
| 
 | ||||
|   @override | ||||
|   CustomizePhysics applyTo(ScrollPhysics? ancestor) { | ||||
|     return CustomizePhysics(parent: buildParent(ancestor)); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   bool shouldAcceptUserOffset(ScrollMetrics position) => false; | ||||
| 
 | ||||
|   @override | ||||
|   bool get allowImplicitScrolling => false; | ||||
| 
 | ||||
|   @override | ||||
|   double applyBoundaryConditions(ScrollMetrics position, double value) { | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Simulation? createBallisticSimulation( | ||||
|       ScrollMetrics position, double velocity) { | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
											
												Binary file not shown.
											
										
									
								| @ -0,0 +1,4 @@ | ||||
| library markdown_editor; | ||||
| 
 | ||||
| export 'package:markdown_editor_ot/src/editor.dart'; | ||||
| export 'package:markdown_editor_ot/src/preview.dart'; | ||||
| @ -0,0 +1,82 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| 
 | ||||
| /// 撤销与前进 | ||||
| class EditPerform { | ||||
|   EditPerform( | ||||
|     this._textEditingController, { | ||||
|     this.initText = '', | ||||
|   }); | ||||
| 
 | ||||
|   /// 最大的存储长度 | ||||
|   final _maxLength = 50; | ||||
| 
 | ||||
|   /// 初始文本 | ||||
|   final String initText; | ||||
| 
 | ||||
|   var _undoList = <_EditData>[]; | ||||
|   var _redoList = <_EditData>[]; | ||||
| 
 | ||||
|   final TextEditingController _textEditingController; | ||||
| 
 | ||||
|   void change(text) { | ||||
|     if (_textEditingController.text != '') { | ||||
|       if (_undoList.isNotEmpty) { | ||||
|         if (_textEditingController.text == _undoList.last.text) return; | ||||
|       } | ||||
|       if (_undoList.length >= _maxLength) _undoList.removeAt(0); | ||||
|       _undoList.add(_EditData(_textEditingController.text, | ||||
|           _textEditingController.selection.baseOffset)); | ||||
|       _redoList.clear(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /// 撤销 | ||||
|   void undo() { | ||||
| //    print(_undoList); | ||||
|     if (_undoList.isNotEmpty) { | ||||
|       _redoList.add(_undoList.last); | ||||
|       _undoList.removeLast(); | ||||
|       if (_undoList.isNotEmpty) { | ||||
|         _textEditingController.value = TextEditingValue( | ||||
|           text: _undoList.last.text, | ||||
|           selection: TextSelection( | ||||
|               extentOffset: _undoList.last.position, | ||||
|               baseOffset: _undoList.last.position), | ||||
|         ); | ||||
|       } else { | ||||
|         _textEditingController.value = TextEditingValue( | ||||
|           text: initText, | ||||
|           selection: TextSelection( | ||||
|               extentOffset: initText.length, baseOffset: initText.length), | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /// 恢复 | ||||
|   void redo() { | ||||
| //    print(_redoList); | ||||
|     if (_redoList.isNotEmpty) { | ||||
|       _textEditingController.value = TextEditingValue( | ||||
|         text: _redoList.last.text, | ||||
|         selection: TextSelection( | ||||
|             extentOffset: _redoList.last.position, | ||||
|             baseOffset: _redoList.last.position), | ||||
|       ); | ||||
|       _undoList.add(_redoList.last); | ||||
|       _redoList.removeLast(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class _EditData { | ||||
|   final String text; | ||||
|   final int position; | ||||
| 
 | ||||
|   _EditData(this.text, this.position); | ||||
| 
 | ||||
|   @override | ||||
|   String toString() { | ||||
|     return 'text:$text position:$position'; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,352 @@ | ||||
| import 'dart:async'; | ||||
| 
 | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:markdown_editor_ot/src/action.dart'; | ||||
| import 'package:markdown_editor_ot/customize_physics.dart'; | ||||
| import 'package:markdown_editor_ot/src/edit_perform.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
| 
 | ||||
| typedef void OnComplete(String content); | ||||
| 
 | ||||
| class MdEditor extends StatefulWidget { | ||||
|   MdEditor({ | ||||
|     Key? key, | ||||
|     this.textStyle, | ||||
|     this.padding = const EdgeInsets.all(0.0), | ||||
|     this.initText, | ||||
|     this.hintText, | ||||
|     this.hintTextStyle, | ||||
|     this.imageSelect, | ||||
|     this.textChange, | ||||
|     this.actionIconColor, | ||||
|     this.cursorColor, | ||||
|     this.appendBottomWidget, | ||||
|     this.splitWidget, | ||||
|     this.textFocusNode, | ||||
|     required this.onComplete, | ||||
|   }) : super(key: key); | ||||
| 
 | ||||
|   final TextStyle? textStyle; | ||||
|   final TextStyle? hintTextStyle; | ||||
|   final EdgeInsetsGeometry padding; | ||||
|   final String? initText; | ||||
|   final String? hintText; | ||||
| 
 | ||||
|   /// see [ImageSelectCallback] | ||||
|   final ImageSelectCallback? imageSelect; | ||||
| 
 | ||||
|   final VoidCallback? textChange; | ||||
| 
 | ||||
|   /// Change icon color, eg: color of font_bold icon. | ||||
|   final Color? actionIconColor; | ||||
| 
 | ||||
|   final Color? cursorColor; | ||||
| 
 | ||||
|   final Widget? appendBottomWidget; | ||||
| 
 | ||||
|   final Widget? splitWidget; | ||||
| 
 | ||||
|   final FocusNode? textFocusNode; | ||||
| 
 | ||||
|   final OnComplete onComplete; | ||||
| 
 | ||||
|   @override | ||||
|   State<StatefulWidget> createState() => MdEditorState(); | ||||
| } | ||||
| 
 | ||||
| class MdEditorState extends State<MdEditor> with AutomaticKeepAliveClientMixin { | ||||
|   final _textEditingController = TextEditingController(text: ''); | ||||
|   var _editPerform; | ||||
|   SharedPreferences? _pres; | ||||
| 
 | ||||
|   String getText() { | ||||
|     return _textEditingController.value.text; | ||||
|   } | ||||
| 
 | ||||
|   // 将文本框光标移动至末尾 | ||||
|   void moveTextCursorToEnd() { | ||||
|     final str = _textEditingController.text; | ||||
|     _textEditingController.value = TextEditingValue(text: str, selection: TextSelection.collapsed(offset: str.length)); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     _textEditingController.text = widget.initText ?? ''; | ||||
| 
 | ||||
|     _editPerform = EditPerform( | ||||
|       _textEditingController, | ||||
|       initText: _textEditingController.text, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   void _disposeText( | ||||
|     ActionType type, | ||||
|     String text, | ||||
|     int index, [ | ||||
|     int? cursorPosition, | ||||
|   ]) { | ||||
|     final _tempKey = 'markdown_editor_${type.toString()}'; | ||||
|     _pres?.setInt(_tempKey, (_pres?.getInt(_tempKey) ?? 0) + 1); | ||||
|     debugPrint('$_tempKey   ${_pres?.getInt(_tempKey)}'); | ||||
| 
 | ||||
|     var position = cursorPosition ?? _textEditingController.selection.base.offset; | ||||
| 
 | ||||
|     if (position < 0) { | ||||
|       print('WARN: The insert position value is $position'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     var startText = _textEditingController.text.substring(0, position); | ||||
|     var endText = _textEditingController.text.substring(position); | ||||
| 
 | ||||
|     var str = startText + text + endText; | ||||
|     _textEditingController.value = | ||||
|         TextEditingValue(text: str, selection: TextSelection.collapsed(offset: startText.length + text.length - index)); | ||||
| 
 | ||||
|     if (widget.textChange != null) widget.textChange!(); | ||||
| 
 | ||||
|     _editPerform.change(_textEditingController.text); | ||||
|   } | ||||
| 
 | ||||
|   /// 获取光标位置 | ||||
|   int _getCursorPosition() { | ||||
|     if (_textEditingController.text.isEmpty) return 0; | ||||
|     if (_textEditingController.selection.base.offset < 0) return _textEditingController.text.length; | ||||
|     return _textEditingController.selection.base.offset; | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _initSharedPreferences() async { | ||||
|     _pres = await SharedPreferences.getInstance(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     super.build(context); | ||||
|     return Stack( | ||||
|       children: [ | ||||
|         Padding( | ||||
|           padding: const EdgeInsets.only(bottom: 40.0), | ||||
|           child: SingleChildScrollView( | ||||
|             child: Padding( | ||||
|               padding: widget.padding, | ||||
|               child: Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 children: <Widget>[ | ||||
|                   TextField( | ||||
|                     maxLines: null, | ||||
|                     minLines: 7, | ||||
|                     textAlignVertical: TextAlignVertical.top, | ||||
|                     cursorColor: widget.cursorColor, | ||||
|                     cursorWidth: 1.5, | ||||
|                     controller: _textEditingController, | ||||
|                     focusNode: widget.textFocusNode, | ||||
|                     autofocus: false, | ||||
|                     scrollPhysics: const CustomizePhysics(), | ||||
|                     style: widget.textStyle ?? | ||||
|                         TextStyle( | ||||
|                           fontSize: 17, | ||||
|                           height: kIsWeb ? null : 1.3, | ||||
|                         ), | ||||
|                     onChanged: (text) { | ||||
|                       _editPerform.change(text); | ||||
|                       if (widget.textChange != null) widget.textChange!(); | ||||
|                     }, | ||||
|                     decoration: InputDecoration( | ||||
|                       hintText: widget.hintText ?? '请输入内容', | ||||
|                       border: InputBorder.none, | ||||
|                       hintStyle: widget.hintTextStyle, | ||||
|                     ), | ||||
|                   ), | ||||
|                   widget.appendBottomWidget ?? const SizedBox(), | ||||
|                 ], | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|         Align( | ||||
|           alignment: Alignment.bottomLeft, | ||||
|           child: Container( | ||||
|             height: 40.0, | ||||
|             width: MediaQuery.of(context).size.width, | ||||
|             child: Ink( | ||||
|               decoration: BoxDecoration( | ||||
|                 color: Theme.of(context).brightness == Brightness.dark ? Colors.black87 : const Color(0xFFF0F0F0), | ||||
|                 boxShadow: [ | ||||
|                   BoxShadow( | ||||
|                       color: | ||||
|                           Theme.of(context).brightness == Brightness.dark ? Colors.black87 : const Color(0xAAF0F0F0)), | ||||
|                 ], | ||||
|               ), | ||||
|               child: FutureBuilder( | ||||
|                 future: _pres == null ? _initSharedPreferences() : null, | ||||
|                 builder: (con, snap) { | ||||
|                   final widgets = <ActionImage>[]; | ||||
| 
 | ||||
|                   widgets.add(ActionImage( | ||||
|                     type: ActionType.done, | ||||
|                     color: widget.actionIconColor, | ||||
|                     tap: (t, s, i, [p]) { | ||||
|                       widget.onComplete(getText()); | ||||
|                     }, | ||||
|                   )); | ||||
| 
 | ||||
|                   widgets.add(ActionImage( | ||||
|                     type: ActionType.undo, | ||||
|                     color: widget.actionIconColor, | ||||
|                     tap: (t, s, i, [p]) { | ||||
|                       _editPerform.undo(); | ||||
|                     }, | ||||
|                   )); | ||||
|                   widgets.add(ActionImage( | ||||
|                     type: ActionType.redo, | ||||
|                     color: widget.actionIconColor, | ||||
|                     tap: (t, s, i, [p]) { | ||||
|                       _editPerform.redo(); | ||||
|                     }, | ||||
|                   )); | ||||
| 
 | ||||
|                   // sort | ||||
|                   if (snap.connectionState == ConnectionState.done || snap.connectionState == ConnectionState.none) | ||||
|                     widgets.addAll(_getSortActionWidgets().map((sort) => sort.widget)); | ||||
| 
 | ||||
|                   return SingleChildScrollView( | ||||
|                     scrollDirection: Axis.horizontal, | ||||
|                     child: Row( | ||||
|                       children: widgets, | ||||
|                     ), | ||||
|                   ); | ||||
|                 }, | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Sort action buttons by used count. | ||||
|   List<_SortActionWidget> _getSortActionWidgets() { | ||||
|     final sortWidget = <_SortActionWidget>[]; | ||||
|     final key = 'markdown_editor'; | ||||
|     final getSortValue = (ActionType type) { | ||||
|       return int.parse((_pres?.get('${key}_${type.toString()}') ?? '0').toString()); | ||||
|     }; | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.image), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.image, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|         imageSelect: widget.imageSelect, | ||||
|         getCursorPosition: _getCursorPosition, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.link), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.link, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.fontBold), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.fontBold, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.fontItalic), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.fontItalic, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.fontStrikethrough), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.fontStrikethrough, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.textQuote), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.textQuote, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.list), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.list, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.h4), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.h4, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.h5), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.h5, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.h1), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.h1, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.h2), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.h2, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
|     sortWidget.add(_SortActionWidget( | ||||
|       sortValue: getSortValue(ActionType.h3), | ||||
|       widget: ActionImage( | ||||
|         type: ActionType.h3, | ||||
|         color: widget.actionIconColor, | ||||
|         tap: _disposeText, | ||||
|       ), | ||||
|     )); | ||||
| 
 | ||||
|     sortWidget.sort((a, b) => (b.sortValue).compareTo(a.sortValue)); | ||||
| 
 | ||||
|     return sortWidget; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   bool get wantKeepAlive => true; | ||||
| } | ||||
| 
 | ||||
| class _SortActionWidget { | ||||
|   final ActionImage widget; | ||||
|   final int sortValue; | ||||
| 
 | ||||
|   _SortActionWidget({ | ||||
|     required this.widget, | ||||
|     required this.sortValue, | ||||
|   }); | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:markdown_core/builder.dart'; | ||||
| import 'package:markdown_core/markdown.dart'; | ||||
| 
 | ||||
| class MdPreview extends StatefulWidget { | ||||
|   MdPreview({ | ||||
|     Key? key, | ||||
|     required this.text, | ||||
|     this.padding = const EdgeInsets.all(0.0), | ||||
|     this.onTapLink, | ||||
|     required this.widgetImage, | ||||
|     this.textStyle, | ||||
|   }) : super(key: key); | ||||
| 
 | ||||
|   final String text; | ||||
|   final EdgeInsetsGeometry padding; | ||||
|   final WidgetImage widgetImage; | ||||
|   final TextStyle? textStyle; | ||||
| 
 | ||||
|   /// Call this method when it tap link of markdown. | ||||
|   /// If [onTapLink] is null,it will open the link with your default browser. | ||||
|   final TapLinkCallback? onTapLink; | ||||
| 
 | ||||
|   @override | ||||
|   State<StatefulWidget> createState() => MdPreviewState(); | ||||
| } | ||||
| 
 | ||||
| class MdPreviewState extends State<MdPreview> | ||||
|     with AutomaticKeepAliveClientMixin { | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     super.build(context); | ||||
|     return SingleChildScrollView( | ||||
|       child: Padding( | ||||
|         padding: widget.padding, | ||||
|         child: LayoutBuilder( | ||||
|           builder: (BuildContext context, BoxConstraints constraints) { | ||||
|             return Markdown( | ||||
|               data: widget.text, | ||||
|               maxWidth: constraints.maxWidth, | ||||
|               linkTap: (link) { | ||||
|                 debugPrint(link); | ||||
|                 if (widget.onTapLink != null) { | ||||
|                   widget.onTapLink!(link); | ||||
|                 } | ||||
|               }, | ||||
|               image: widget.widgetImage, | ||||
|               textStyle: widget.textStyle, | ||||
|             ); | ||||
|           }, | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   bool get wantKeepAlive => true; | ||||
| } | ||||
| 
 | ||||
| typedef void TapLinkCallback(String link); | ||||
| @ -0,0 +1,61 @@ | ||||
| name: markdown_editor_ot | ||||
| description: Simple and easy to implement your markdown editor, it uses its own parser. | ||||
| version: 1.0.2 | ||||
| homepage: https://github.com/xia-weiyang/markdown_editor_ot | ||||
| 
 | ||||
| environment: | ||||
|   sdk: '>=2.12.0 <3.0.0' | ||||
| 
 | ||||
| dependencies: | ||||
|   flutter: | ||||
|     sdk: flutter | ||||
| 
 | ||||
|   shared_preferences: ^2.0.4 | ||||
|   markdown_core: ^1.0.0 | ||||
| 
 | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|     sdk: flutter | ||||
| 
 | ||||
| # For information on the generic Dart part of this file, see the | ||||
| # following page: https://www.dartlang.org/tools/pub/pubspec | ||||
| 
 | ||||
| # The following section is specific to Flutter. | ||||
| flutter: | ||||
| 
 | ||||
|   # To add assets to your package, add an assets section, like this: | ||||
|   # assets: | ||||
|   #  - images/a_dot_burr.jpeg | ||||
|   #  - images/a_dot_ham.jpeg | ||||
|   # | ||||
|   # For details regarding assets in packages, see | ||||
|   # https://flutter.io/assets-and-images/#from-packages | ||||
|   # | ||||
|   # An image asset can refer to one or more resolution-specific "variants", see | ||||
|   # https://flutter.io/assets-and-images/#resolution-aware. | ||||
| 
 | ||||
|   # To add custom fonts to your package, add a fonts section here, | ||||
|   # in this "flutter" section. Each entry in this list should have a | ||||
|   # "family" key with the font family name, and a "fonts" key with a | ||||
|   # list giving the asset and other descriptors for the font. For | ||||
| 
 | ||||
|   fonts: | ||||
|     - family: MyIconFont | ||||
|       fonts: | ||||
|         - asset: packages/markdown_editor_ot/fonts/iconfont.ttf | ||||
| 
 | ||||
|   # example: | ||||
|   # fonts: | ||||
|   #   - family: Schyler | ||||
|   #     fonts: | ||||
|   #       - asset: fonts/Schyler-Regular.ttf | ||||
|   #       - asset: fonts/Schyler-Italic.ttf | ||||
|   #         style: italic | ||||
|   #   - family: Trajan Pro | ||||
|   #     fonts: | ||||
|   #       - asset: fonts/TrajanPro.ttf | ||||
|   #       - asset: fonts/TrajanPro_Bold.ttf | ||||
|   #         weight: 700 | ||||
|   # | ||||
|   # For details regarding fonts in packages, see | ||||
|   # https://flutter.io/custom-fonts/#from-packages | ||||
| @ -0,0 +1,112 @@ | ||||
| import 'package:cached_network_image/cached_network_image.dart'; | ||||
| import 'package:dde_gesture_manager/constants/constants.dart'; | ||||
| import 'package:dde_gesture_manager/extensions.dart'; | ||||
| import 'package:dde_gesture_manager/models/settings.provider.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:markdown_editor_ot/markdown_editor.dart'; | ||||
| import 'package:url_launcher/url_launcher.dart'; | ||||
| 
 | ||||
| class DMarkdownField extends StatefulWidget { | ||||
|   const DMarkdownField({ | ||||
|     Key? key, | ||||
|     required this.initText, | ||||
|     required this.onComplete, | ||||
|     required this.readOnly, | ||||
|   }) : super(key: key); | ||||
| 
 | ||||
|   final bool readOnly; | ||||
|   final String? initText; | ||||
|   final OnComplete onComplete; | ||||
| 
 | ||||
|   @override | ||||
|   _DMarkdownFieldState createState() => _DMarkdownFieldState(); | ||||
| } | ||||
| 
 | ||||
| class _DMarkdownFieldState extends State<DMarkdownField> { | ||||
|   String? _previewText; | ||||
| 
 | ||||
|   bool get isPreview => _previewText != null || widget.readOnly; | ||||
| 
 | ||||
|   final FocusNode _focusNode = FocusNode(); | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     _previewText = widget.initText; | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   _launchURL(String url) async { | ||||
|     if (await canLaunch(url)) { | ||||
|       await launch(url); | ||||
|     } else { | ||||
|       throw 'Could not launch $url'; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void didUpdateWidget(covariant DMarkdownField oldWidget) { | ||||
|     if (oldWidget.initText != widget.initText) { | ||||
|       setState(() { | ||||
|         _previewText = widget.initText; | ||||
|       }); | ||||
|     } | ||||
|     super.didUpdateWidget(oldWidget); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Focus( | ||||
|       child: Builder(builder: (context) { | ||||
|         return Container( | ||||
|           decoration: BoxDecoration( | ||||
|             borderRadius: BorderRadius.circular(defaultBorderRadius), | ||||
|             color: Colors.grey.withOpacity(.3), | ||||
|             border: Border.all( | ||||
|                 width: 2, | ||||
|                 color: Focus.of(context).hasFocus && !widget.readOnly | ||||
|                     ? context.watch<SettingsProvider>().activeColor ?? Color(0xff565656) | ||||
|                     : Color(0xff565656)), | ||||
|           ), | ||||
|           child: isPreview | ||||
|               ? GestureDetector( | ||||
|                   onTap: widget.readOnly | ||||
|                       ? null | ||||
|                       : () { | ||||
|                           setState(() { | ||||
|                             _previewText = null; | ||||
|                           }); | ||||
|                         }, | ||||
|                   child: MouseRegion( | ||||
|                     cursor: widget.readOnly ? SystemMouseCursors.basic : SystemMouseCursors.click, | ||||
|                     child: MdPreview( | ||||
|                       text: _previewText ?? '', | ||||
|                       padding: EdgeInsets.only(left: 15), | ||||
|                       onTapLink: _launchURL, | ||||
|                       widgetImage: (imageUrl) => CachedNetworkImage( | ||||
|                         imageUrl: imageUrl, | ||||
|                         placeholder: (context, url) => const SizedBox( | ||||
|                           width: double.infinity, | ||||
|                           height: 300, | ||||
|                           child: Center(child: CircularProgressIndicator()), | ||||
|                         ), | ||||
|                         errorWidget: (context, url, error) => const Icon(Icons.error), | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ) | ||||
|               : MdEditor( | ||||
|                   initText: widget.initText, | ||||
|                   textFocusNode: _focusNode, | ||||
|                   padding: EdgeInsets.symmetric(horizontal: 5), | ||||
|                   onComplete: (content) { | ||||
|                     setState(() { | ||||
|                       _previewText = content; | ||||
|                     }); | ||||
|                     widget.onComplete(content); | ||||
|                   }, | ||||
|                 ), | ||||
|         ); | ||||
|       }), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue