commit aa6dee90bea053baf51cfb58fb3cf147357cd82d Author: lensferno Date: Fri Mar 26 17:05:06 2021 +0800 重置项目结构 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc49a05 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/out +/files +/caches +/target +*.token +/target/ +/log/ +/logs/ +.idea \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b14ca0a --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md new file mode 100644 index 0000000..810d374 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ + +# 一个用来点名的玩意/A simple guy to choose names + +![图片加载不出来欸~](https://github.com/lensferno/dogename/raw/main/res/top.png "哟嚯!") + +看下面 + + +## 介绍/Introduce +这是一个基于Java语言,以Google Material Design(Google MD)为设计风格的,用来点名的东西。 + +基本上不会有什么大更新,就是改善代码而已了ヾ§  ̄▽)ゞ + +由于时间仓促,加上还是JAVA的新手,因此代码和算法写的很烂,望谅解ヽ(╯▽╰)ノ + +------------ + + +#### 用法介绍 +[去去去➡](https://github.com/lensferno/dogename/blob/main/res/usage.md) + +## 截图/Screenshot: + +#### [来来来~](https://github.com/lensferno/dogename/blob/main/res/you-want.md "我要康康") + + + +## 下载/Download: +[来这里](https://github.com/lensferno/dogename/releases "这里") + + +## 使用到的第三方库/Third-party library used: + +- [JFoenix](https://github.com/jfoenixadmin/JFoenix "JFoenix")(8.0.4),UI界面库。 + +- [Apache Commons Codec](http://commons.apache.org/proper/commons-codec/ "Apache Commons Codec")(1.11),用于Base64解码。 + +- [Gson](https://github.com/google/gson "Gson")(2.8.5),用于Json数据的解析与生成。 + +- [OkHttp3](https://github.com/square/okhttp "OkHttp")(4.2.2),用于语音部分的数据请求。 + +- [gushici](https://github.com/xenv/gushici/ "古诗词")项目提供的古诗词接口和数据。 + +- “每日一句话”的数据来自[一言](https://hitokoto.cn/ "一言") + +- 本项目还使用了 百度AI SDK 来实现OCR功能。 + +------ + +#### License信息 + +本程序使用[GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl-3.0.html "LGPL") (LGPL,version 3)开源许可证, + + + +遵循[Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0 "Apache License 2.0")使用了以下库: + +- [JFoenix](https://github.com/jfoenixadmin/JFoenix "JFoenix")(8.0.4) + +- [Apache Commons Codec](http://commons.apache.org/proper/commons-codec/ "Apache Commons Codec")(1.11) + +- [Gson](https://github.com/google/gson "Gson")(2.8.5) + +- [OkHttp3](https://github.com/square/okhttp "OkHttp")(4.2.2) + + + + diff --git a/dogename.iml b/dogename.iml new file mode 100644 index 0000000..bad4288 --- /dev/null +++ b/dogename.iml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2cba667 --- /dev/null +++ b/pom.xml @@ -0,0 +1,109 @@ + + + 4.0.0 + + me.lensferno.dogename + dogename + 3.3 + + + 1.8 + 1.8 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + me.lensferno.dogename.Main + + + + + + + + + + + com.google.code.gson + gson + 2.8.6 + + + + + commons-codec + commons-codec + 1.14 + + + + + com.jfoenix + jfoenix + 8.0.9 + + + + + org.apache.logging.log4j + log4j-core + 2.13.2 + + + + + commons-io + commons-io + 2.6 + + + + + com.squareup.okhttp3 + okhttp + 4.2.2 + + + + + com.googlecode.soundlibs + mp3spi + 1.9.5.4 + + + + com.baidu.aip + java-sdk + 4.12.0 + + + + + + + + central + aliyun maven + http://maven.aliyun.com/nexus/content/groups/public/ + default + + + true + + + + false + + + + + \ No newline at end of file diff --git a/res/icon.ico b/res/icon.ico new file mode 100644 index 0000000..5e66e54 Binary files /dev/null and b/res/icon.ico differ diff --git a/res/top.png b/res/top.png new file mode 100644 index 0000000..052635e Binary files /dev/null and b/res/top.png differ diff --git a/res/usage.md b/res/usage.md new file mode 100644 index 0000000..dda968f --- /dev/null +++ b/res/usage.md @@ -0,0 +1,229 @@ +# 我该如何使用Dogename?(适用于最新的版本) + +*哈哈,终于开始写了,我都说鸽鸽我呀是不会咕的嘛*~ ╮(‵▽′)╭ + +此文章是Dogename的使用说明,它将指导您如何更好地使用这个点名工具。 + +> *使用一样新东西之前看看使用说明是个好习惯。* 🤔 *——我说的* + +这个使用说明分为以下几个部分:(点击可直达) + +### 1. 安装&开始使用 +- [从哪弄来?](#从哪弄来) +- [怎么配置环境?(很简单的!)](#怎么配置环境) +- [运行&使用](#运行与使用) + +### 2. 名单管理 +- [添加一个名字](#添加一个名字) +- [懒人:批量添加名字(特别棒!)](#批量添加名字) + - 文字识别法 + - 复制粘贴法 +- [删除名字](#删除名字) +- [导入&导出名单](#名单的导入和导出) +- [打乱名字](#打乱名字) + +### 3. 选项设置 +- [点名方面的](#点名方面的设置) + - 点名规则 + - 挑选次数 + - 挑选速度 + - 使用/不使用随机性更强的Java SecureRandom + - 开启/不开启语言播报 +- [语音报方面的](#语音播报方面的设置) + + +### 4. 其他小功能的介绍&说明 +- [历史记录](#历史记录) +- [小窗模式](#小窗模式) + + + + + + +-------------------------------------------- + +被夹在分割线之中不得动弹~ + +-------------------------------------------- + + + + + + + +# 开始:使用说明 + + + +## 1. 安装&开始使用 + + + +### 从哪弄来 +- 呃嗯嗯嗯嗯嗯🤔...怎么说呢,既然你能来到这里,基本上你已经有Dogename了吧? + +- 如果还真没有,那就去这里吧:[Github](https://github.com/eatenid/dogename/releases) +> 说一声: +> 文件“dogename.jar”为主程序文件。 +> “dogename_with_jre”之类的文件是带有Java运行库的整合版本,如果您下载的是这个整合包,那么您就不必再配置运行环境,跳过b步骤了。 + +不过在中国大陆内,Github的访问速度普遍偏慢,因此建议您下载不带运行环境的包(dogeneme_no_jre),或者去下载页(releases页)给出的其他下载方式。 + +### 怎么配置环境 +本程序是用Java语言写成的,因此您的计算机需要有合适的Java运行环境才能运行Dogename。(跟Minecraft一样的道理) + +- 如果您是从本程序过来的,那么恭喜,您不用配置环境了!🥳 + +- 如果您下载的是附带有Java运行环境的Dogename,那么您也不需要配置Java运行环境。 + +- 如果您都不是以上,您可以到[Java官网](https://www.java.com/)下载并安装,安装完成后,就好了。 + +### 运行与使用 +- 很简单,如果您的Java环境已经没问题了,就可以直接运行“dogename.exe”开始玩耍。 +- 您也可以运行“dogename_hide.exe”来隐式运行dogename(就是不会有黑框框显示出来),不过直接使用“dogename.exe”可以*在一定程度上*帮助您排查为何不能运行(如果您按照说明去做*一般*不会出现这种情况)。 +- 成功运行后,点击“安排一下”即可开始点名,不过此时还没有任何名字在名单中,因此您需要至少添加一个名字(或者先使用“数字模式”玩玩)。下面讲讲述如何添加一个或多个名字。 + + + +-------- + + + +## 2. 名单管理 + +首先,您需要点击主界面上的“名单管理”按钮,呼出名单管理面板,以便进行操作。此时名单列表会列出已经添加的名字。 + +### 添加一个或几个名字 + +1. 在名字输入框中输入想要添加的名字,如果输入多行名字,则可以同时添加对个名字(每一行识别为一个名字)。 +2. 输入完成后,点击"添加"按钮,即可在名单列表中看到刚刚添加进去的名字。 + +### 批量添加名字 +> 在上面“添加一个或几个名字”提到过,如果一行输入了一个名字,就可以同时添加多个名字(每一行识别为一个名字)。 +因此,根据这个原理,可以实现批量添加名字。 + +以下提供两种批量添加名字的方法: + +*(您也可以自己摸索其他的批量添加方法,只要最后能够使得名字输入框中每行拥有一个名字即可)* + + +##### 1. 通过Dogename自带的OCR(文字识别)功能来截取屏幕上的名字。 +- 点击名单管理面板上的“从屏幕上截取名字”,打开OCR模块。 +- 打开其他含有欲添加名单的文件*(例如Excel表格、Word文档、座位表图片等或者其他显示了名字的程序)*。 +- 然后切换到Dogename的文字识别窗口(注意请使显示了名字的界面保持显示),点击“截屏并开始识别”按钮。此时Dogename的界面将会被隐藏,以便进行截图操作。等待大约0.5秒,屏幕将会出现跟随鼠标位置的竖线和横线,这是方便您剪裁定位的。 +- 点击鼠标左键,选取*含有名字的区域*,松开鼠标后,将会完成截屏操作并开始识别。 +- 识别完成后,文字识别界面左侧的文本框将会显示出识别出的名字。如果文字关系清楚,识别出来的结果就是一行一个名字。如果不是,您可以手动修改,使得*一行只有一个名字* +- 修改完成后,将识别结果复制下来,粘贴在名字输入框中。点击“添加”按钮,即可完成添加。 + +下面的动图演示了如何进行这一操作: + + + + +![如果图片没有显示出来的话请直接打开:https://www.example.com](https://www.example.com/gif.gif) + + + + +##### 2. 从Word、Excel等含有表格式名单列表的地方复制粘贴。 +- 如果因为网络不畅或者其他原因无法使用文字识别功能,您可以使用这种办法。 +- 在其中的表格里,如果竖着选中文本,复制粘贴到名单输入框后一般就能够一行一个名字。点击“添加”按钮,即可批量添加上名字。 + +下面的动图演示了如何进行这一操作: + + + + +![如果图片没有显示出来的话请直接打开:https://www.example.com](https://www.example.com/gif.gif) + + + + +### 删除名字 +- 很简单,只需要在名单列表中选中欲删除的名字,点击“删除”按钮即可。 +- 点击“删除所有”按钮会删除名单列表中的所有名字。 +- 注意:除非已经备份好名单,否则无法撤销,请小心操作。 + +### 名单的导入和导出 +- 点击“备份”按钮,选择将要保存名单的地方,输入好文件名,点击确定,即可保存。 +- 点击“恢复”按钮,选择导出过的名单文件,点击确定,即可导入。 +注意:**导入名单会直接覆盖现有名单**,因此建议您在导入之前备份好现有名单。 + +### 打乱名字 +- 点击“打乱顺序”按钮,将会把名单中的名字随机排列,在*一定程度上(不是很严格地)*提高随机性。 + + + +-------- + + + +## 3. 选项设置 + + + +### 点名的设置 + +这里讲介绍一下几个方面的设置: +1. 点名规则 +2. 挑选次数 +3. 挑选速度 +4. 使用/不使用随机性更强的Java SecureRandom +5. 开启/不开启语言播报 + + + +-------------这是分割线------------- + + + +##### 1. 点名规则 +- 通过设置此项,可以按以下规则进行挑选: + - ①被点过的名字还要被点 + - ②被点过的名字不会再被点(默认使用) + - ~~娱乐模式*(①模式下可用)* ~~ *(已移除)* + - 机会均等*(②模式下可用,默认使用)* + +介绍: +- **娱乐模式**:旧称“套路模式”,勾选后会使被点过的名字在挑选列表中多出现4到5次,增加再次被点中的几率。 +**注意:仅在勾选此模式后点中的名字才会被多增加4到5次,不勾选时选中的名字不受影响。 +退出后会自动重置,不影响下次使用。** + +- **机会均等**:勾选“机会均等”后,将会保存已点过的的名字和数字到文件中,下次启动时仍不会被点到,直到全部名字或数字被点完 或点击“机会均等”的“重置”按钮。 +**注意:仅保存“这次点过就不点了”模式下选中的名字或数字。*** + + +##### 2. 挑选次数 +- 您可以调节名字随机滚动的次数,滚动显示多少个名字后,才是真正被选中的名字。 +--范围:3至200次 +--默认值:随机次数(范围:100至250次) +~~小问题:这个次数是不怎么准确的~~😓 + +##### 3. 挑选速度 +- 通过调节滑动条,您可以设置名字滚动的速度。数值越大速度越快。若调节为0,则显示一个名字后,会过100ms才显示下一个名字,直至出现正真被挑选中的名字。默认值:80 (20ms) + +##### 4. 设置是否使用Java SecureRandom +- 开启后,将使用Java SecureRandom来获得较强随机性的随机数,而不是普通的随机数算法。默认开启。如果您觉得开启后点名明显变卡(虽说不太可能),可以尝试关闭。 + +##### 5.设置是否开启语言播报 +- 开启后,点中名字后将会把被选中的名字用语音播放出来。默认开启。需要网络支持。如果因为各种原因无法/没必要播放,可以关闭这个功能。 + + +### 语音播报的设置 +- 在这里,你可以设置播报人,以及其语速和语调(默认都是5)。 + + +-------- + + + +## 4. 其他小功能的介绍&说明 + +#### 1. 历史记录 +- 在这里,你可以查看最近2000条点名记录。当记录超过2000条时,将会自动清空历史记录,重新从0开始记录,当然,您也可以手动清空。 +- 在搜索框输入文字后,点击“向上查找”或者“向下查找”按钮,可以查找出包含有您想要搜索的文字的记录。 +~~(该功能现阶段状况:容易出bug~~😫~~,搜寻替代方案ing...)~~ +#### 2. 小窗模式 +- 点击主界面的“小窗模式”按钮,可以将窗口变成小版界面,仅保留“安排一下”和“恢复”按钮,以及一个用于显示名字的文本。这个时候窗口总在最前端,拖动非按钮区域可以移动窗口。点击“恢复”按钮即可恢复原来的窗口状态。 \ No newline at end of file diff --git a/res/you-want.md b/res/you-want.md new file mode 100644 index 0000000..097aa71 --- /dev/null +++ b/res/you-want.md @@ -0,0 +1,41 @@ +# 你想瞅一瞅的截图 +您看好了啊🧐 + +*此截图为Windows 10下的效果,不同的系统**可能**会有不同的效果* + +*这里的截图不是最新的版本,因此可能会有一定的差别,请以实物为准* + +## 1. 第一界面 +#### a. 古诗词: + +![gushi.png](https://i.loli.net/2020/05/04/1epMwgTNjC9X4lL.png) + +#### b. 一言: + +![hitokoto.png](https://i.loli.net/2020/05/04/95z3XM4lICvxiPQ.png) + +## 2. 主界面 +#### a. 未挑选时: + +![main_interfoce.png](https://i.loli.net/2020/05/04/WfnsbLTqkcBvhCZ.png) + +#### b. 选中一个名字: +![main_interface_chose.png](https://i.loli.net/2020/05/04/xvVuIzC51OsXjN3.png) + +## 3. “迷你模式”界面 +![mini_pane.png](https://i.loli.net/2020/05/04/y2rbYRHdfl8aQ1e.png) + +## 4. “名单管理”界面 +![name_mamager_pane.png](https://i.loli.net/2020/05/04/7JHnDdCKqgo3Ska.png) + +## 5. 设置界面 +![settings_pane.png](https://i.loli.net/2020/05/04/5FlSLMxGN6iDtTz.png) + +## 6. OCR模块界面 +![ocr.png](https://i.loli.net/2020/05/04/QosZRfKagl1IjNC.png) + +## 7. “程序信息”界面 +![info_pane.png](https://i.loli.net/2020/05/04/i8dHWVvpTCbylzj.png) + +## 8. 还有更多的吗? +[下载](https://github.com/eatenid/dogename/releases "下载")下来看看吧😀 \ No newline at end of file diff --git a/src/main/java/log4j2.xml b/src/main/java/log4j2.xml new file mode 100644 index 0000000..92d39c3 --- /dev/null +++ b/src/main/java/log4j2.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/me/lensferno/dogename/DataReleaser.java b/src/main/java/me/lensferno/dogename/DataReleaser.java new file mode 100644 index 0000000..4bc428e --- /dev/null +++ b/src/main/java/me/lensferno/dogename/DataReleaser.java @@ -0,0 +1,21 @@ +package me.lensferno.dogename; + +import me.lensferno.dogename.resources.MainInterfaceImage; +import me.lensferno.dogename.resources.dogename; +import org.apache.commons.codec.binary.Base64; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +public class DataReleaser { + + public static InputStream getDogenameStream(){ + return new ByteArrayInputStream(Base64.decodeBase64(dogename.data)); + } + + public static InputStream getMainPicStream(){ + return new ByteArrayInputStream(Base64.decodeBase64(MainInterfaceImage.data)); + } + + +} diff --git a/src/main/java/me/lensferno/dogename/Main.java b/src/main/java/me/lensferno/dogename/Main.java new file mode 100644 index 0000000..ec00d41 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/Main.java @@ -0,0 +1,66 @@ +package me.lensferno.dogename; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; +import me.lensferno.dogename.configs.ConfigLoader; +import me.lensferno.dogename.controllers.MainInterfaceController; +import me.lensferno.dogename.sayings.Gushici; +import me.lensferno.dogename.sayings.Hitokoto; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Random; + +public class Main extends Application { + + Logger log = LogManager.getLogger(); + + public static void main(String[] args){ launch(args);} + + @Override + public void start(Stage primaryStage) { + FXMLLoader fxmlLoader; + Parent parent; + + try{ + fxmlLoader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/MainInterface.fxml")); + parent=fxmlLoader.load(); + }catch (Exception e){ + log.error("Error to load main interface FXML :"+e.toString()); + return; + } + + Scene scene=new Scene(parent,990,700); + primaryStage.setTitle("DogeName 叁号姬"); + primaryStage.setScene(scene); + + primaryStage.show(); + + ConfigLoader configLoader=new ConfigLoader(); + + MainInterfaceController mainInterfaceController=fxmlLoader.getController(); + + mainInterfaceController.setToggleGroup(); + + mainInterfaceController.setUpConfig(configLoader); + + mainInterfaceController.bindProperties(); + + mainInterfaceController.setImg(DataReleaser.getMainPicStream()); + + primaryStage.setOnCloseRequest(event -> configLoader.writeAllConfigToFile(configLoader.getMainConfigLocation(),configLoader.getVoiceConfigLocation())); + + if (mainInterfaceController.getMainConfig().isShowSaying()) { + if (new Random().nextBoolean()){ + new Gushici().showGushici(mainInterfaceController.getRootPane(),mainInterfaceController.getTopBar()); + }else { + new Hitokoto().showHitokoto(mainInterfaceController.getRootPane(),mainInterfaceController.getTopBar()); + } + } + + } + +} \ No newline at end of file diff --git a/src/main/java/me/lensferno/dogename/choose/Chooser.java b/src/main/java/me/lensferno/dogename/choose/Chooser.java new file mode 100644 index 0000000..19574cb --- /dev/null +++ b/src/main/java/me/lensferno/dogename/choose/Chooser.java @@ -0,0 +1,356 @@ +package me.lensferno.dogename.choose; + +import com.jfoenix.controls.JFXButton; +import javafx.animation.AnimationTimer; +import javafx.beans.property.StringProperty; +import me.lensferno.dogename.configs.VoiceConfig; +import me.lensferno.dogename.data.History; +import me.lensferno.dogename.data.NameData; +import me.lensferno.dogename.voice.Token; +import me.lensferno.dogename.voice.VoicePlayer; + +import java.security.SecureRandom; +import java.util.Random; +import java.util.logging.Logger; + + /* + +┴┬┴┬/ ̄\_/ ̄\ +┬┴┬┴▏  ▏▔▔▔▔\ +┴┬┴/\ /      ﹨ +┬┴∕       /   ) +┴┬▏        ●  ▏ +┬┴▏           ▔█  +┴◢██◣     \___/ +┬█████◣       /   +┴█████████████◣ +◢██████████████▆▄ +█◤◢██◣◥█████████◤\ +◥◢████ ████████◤   \ +┴█████ ██████◤      ﹨ +┬│   │█████◤        ▏ +┴│   │              ▏ +┬ ∕    ∕    /▔▔▔\     ∕ +┴/___/﹨   ∕     ﹨  /\ +┬┴┬┴┬┴\    \      ﹨/   ﹨ +┴┬┴┬┴┬┴ \___\     ﹨/▔\﹨ ▔\ +▲△▲▲╓╥╥╥╥╥╥╥╥\   ∕  /▔﹨/▔﹨ + **╠╬╬╬╬╬╬╬╬*﹨  /  // + + */ +//一坨屎山,有待修改😒 + +public final class Chooser { + + Logger log =Logger.getLogger("ChooserLogger"); + + final int UPPER_LABEL_ID = 1; + final int UNDER_LABEL_ID = 2; + + + Token token; + VoicePlayer voicePlayer; + + VoiceConfig voiceConfig; + + Random random =new Random(); + + public short minNumber; + public short maxNumber; + + boolean voicePlay=true; + + int totalMaxCount =120; + int cycleMaxCount =0; + + int totalCount =0; + int totalCycleCount =0; + + int shownLabelId =1; + + String chosenName; + + boolean cycleEnd =true; + boolean ignoreTimesOut=false; + boolean ignorePast=true; + + boolean equalMode=true; + + boolean forceStop =false; + + boolean newAlgo=true; + + public JFXButton anpaiBtn; + + public short speed; + + NameData nameData; + + boolean isRunning; + + StringProperty upLabelText; + StringProperty downLabelText; + + History history; + + String speaker,speakSpeed,intonation; + + void writeIgnoreList(){ + nameData.writeIgnoreList(""); + } + + + AnimationTimer timer =new AnimationTimer() { + @Override + public void handle(long now) { + + if(forceStop){ + totalCount = totalMaxCount +1; + } + + try{ + Thread.sleep(speed); + }catch (Exception e){e.printStackTrace(); } + + if(totalCount >= totalMaxCount){ + if(!nameData.getIgnoreNameList().contains(chosenName)||!ignorePast||forceStop){ + + forceStop=false; + + if(ignorePast) + nameData.getIgnoreNameList().add(chosenName); + if(equalMode) + writeIgnoreList(); + + cycleEnd=true; + totalCount =0; + totalCycleCount =0; + ignoreTimesOut=false; + + switch (shownLabelId){ + case UPPER_LABEL_ID:{ + + if(downLabelText.get().contains("→")||downLabelText.get().contains("←")) + downLabelText.set(downLabelText.get().replace("→ ","").replace(" ←","")); + + upLabelText.set("→ "+chosenName+" ←"); + + break; + } + case UNDER_LABEL_ID:{ + if(upLabelText.get().contains("→")||upLabelText.get().contains("←")) + upLabelText.set(upLabelText.get().replace("→ ","").replace(" ←","")); + + downLabelText.set("→ "+chosenName+" ←"); + + break; + } + } + isRunning=false; + anpaiBtn.setText("安排一下"); + stop(); + System.gc(); + history.addHistory(chosenName); + if(voicePlay) + voicePlayer.playVoice(chosenName,speaker,intonation,speakSpeed); + return; + }else + ignoreTimesOut=true; + + + + } + if(totalCycleCount >= cycleMaxCount &&!ignoreTimesOut){ + cycleEnd=true; + totalCycleCount =0; + } + + if(cycleEnd){ + //times=(int)(1+Math.random()*(chosenTime-already)); + cycleMaxCount =1+random.nextInt(totalMaxCount - totalCount +1); + cycleEnd=false; + //showWhich=(int)(1+Math.random()*2); + shownLabelId =1+random.nextInt(2); + } + + + + switch (shownLabelId){ + case UPPER_LABEL_ID:{ + chosenName= nameData.randomGet(); + upLabelText.set(chosenName); + totalCount++; + totalCycleCount++; + break; + } + + case UNDER_LABEL_ID:{ + chosenName= nameData.randomGet(); + downLabelText.set(chosenName); + totalCount++; + totalCycleCount++; + break; + } + } + + + } + }; + //--------------------------------------------------------------------------------------- + SecureRandom secRandom =new SecureRandom(); + AnimationTimer numbTimer =new AnimationTimer() { + @Override + public void handle(long now) { + + if(forceStop){ + totalCount = totalMaxCount +1; + } + + try{ + Thread.sleep(speed); + }catch (Exception e){e.printStackTrace(); } + + if(totalCount >= totalMaxCount){ + if(!nameData.getIgnoreNumberList().contains(chosenName)||!ignorePast||forceStop){ + + forceStop=false; + + if(ignorePast) + nameData.getIgnoreNumberList().add(chosenName); + if(equalMode) + writeIgnoreList(); + + cycleEnd=true; + totalCount =0; + totalCycleCount =0; + ignoreTimesOut=false; + + + switch (shownLabelId){ + case UPPER_LABEL_ID:{ + if(downLabelText.get().contains("→")||downLabelText.get().contains("←")) + downLabelText.set(downLabelText.get().replace("→ ","").replace(" ←","")); + + upLabelText.set("→ "+chosenName+" ←"); + + break; + } + case UNDER_LABEL_ID:{ + if(upLabelText.get().contains("→")||upLabelText.get().contains("←")) + upLabelText.set(upLabelText.get().replace("→ ","").replace(" ←","")); + + downLabelText.set("→ "+chosenName+" ←"); + + break; + } + } + isRunning=false; + anpaiBtn.setText("安排一下"); + stop(); + System.gc(); + history.addHistory(chosenName); + if(voicePlay) + voicePlayer.playVoice(chosenName,speaker,intonation,speakSpeed); + return; + }else + ignoreTimesOut=true; + + } + + shownLabelId =1+random.nextInt(2); + //speed=(short)(65+random.nextInt(100)); + + switch (shownLabelId){ + case UPPER_LABEL_ID:{ + if(newAlgo) + chosenName=String.valueOf(minNumber+random.nextInt(maxNumber-minNumber+1)); + else + chosenName=String.valueOf(minNumber+secRandom.nextInt(maxNumber-minNumber+1)); + + upLabelText.set(chosenName); + totalCount++; + totalCycleCount++; + break; + } + + case UNDER_LABEL_ID:{ + if(newAlgo) + chosenName=String.valueOf(minNumber+random.nextInt(maxNumber-minNumber+1)); + else + chosenName=String.valueOf(minNumber+secRandom.nextInt(maxNumber-minNumber+1)); + + downLabelText.set(chosenName); + totalCount++; + totalCycleCount++; + break; + } + } + + + } + }; + + public void forceStop(){ + + } + + + + public void run(short speed,int chosenTime,boolean ignorePast,boolean equalMode,boolean voicePlay){ + + this.speed = speed; + this.totalMaxCount = chosenTime; + this.ignorePast = ignorePast; + this.equalMode = equalMode; + this.voicePlay = voicePlay; + + isRunning=true; + timer.start(); + } + + public void run(short maxNumber,short minNumber,short speed,int chosenTime,boolean ignorePast,boolean equalMode,boolean voicePlay){ + this.maxNumber = maxNumber; + this.minNumber = minNumber; + this.speed = speed; + this.totalMaxCount = chosenTime; + this.ignorePast = ignorePast; + this.equalMode = equalMode; + this.voicePlay = voicePlay; + + isRunning=true; + numbTimer.start(); + } + + public void set(StringProperty upLabelText, StringProperty downLabelText, JFXButton anpaiBtn, History history, NameData nameData, Token token, VoiceConfig voiceConfig){ + + this.upLabelText=upLabelText; + this.downLabelText=downLabelText; + + this.anpaiBtn = anpaiBtn; + this.history = history; + this.nameData = nameData; + + this.token=token; + this.voicePlayer=new VoicePlayer(token); + + this.voiceConfig=voiceConfig; + + this.speaker=String.valueOf(voiceConfig.getSpeaker()); + this.speakSpeed=String.valueOf(voiceConfig.getSpeed()); + this.intonation=String.valueOf(voiceConfig.getIntonation()); + this.speaker=voiceConfig.getSpeaker(); + } + + + public void setChoose(JFXButton anpaiBtn) { + this.anpaiBtn = anpaiBtn; + } + + public boolean isRunning() { + return isRunning; + } + + public void setForceStop(boolean forceStop) { + this.forceStop = forceStop; + } +} diff --git a/src/main/java/me/lensferno/dogename/configs/ConfigLoader.java b/src/main/java/me/lensferno/dogename/configs/ConfigLoader.java new file mode 100644 index 0000000..ce759d2 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/ConfigLoader.java @@ -0,0 +1,212 @@ +package me.lensferno.dogename.configs; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import javafx.beans.property.*; +import me.lensferno.dogename.configs.adapters.BooleanPropertyAdapter; +import me.lensferno.dogename.configs.adapters.DoublePropertyAdapter; +import me.lensferno.dogename.configs.adapters.IntegerPropertyAdapter; +import me.lensferno.dogename.configs.adapters.StringPropertyAdapter; +import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +public class ConfigLoader { + + Logger log = LogManager.getLogger(); + + //ConfigValuesBean config; + private MainConfig mainConfig; + private VoiceConfig voiceConfig; + + private final String mainConfigLocation = "files"+ File.separator+"Config.json"; + private final String voiceConfigLocation = "files"+ File.separator+"VoiceConfig.json"; + + public String getMainConfigLocation() { + return mainConfigLocation; + } + + public String getVoiceConfigLocation() { + return voiceConfigLocation; + } + + public MainConfig getMainConfig() { + return mainConfig; + } + + public MainConfig readConfigFromFile(String fileLocation){ + + //property属性应该要自定义一个json适配器才能解析出来 + Gson gson=new GsonBuilder() + .registerTypeAdapter(SimpleBooleanProperty.class,new BooleanPropertyAdapter()) + .registerTypeAdapter(SimpleIntegerProperty.class,new IntegerPropertyAdapter()) + .registerTypeAdapter(SimpleStringProperty.class,new StringPropertyAdapter()) + .registerTypeAdapter(SimpleDoubleProperty.class,new DoublePropertyAdapter()) + .setPrettyPrinting() + .create(); + + String ConfigJSON; + + try{ + File configFile=new File(fileLocation); + if(!configFile.exists()){ + configFile.getParentFile().mkdirs(); + configFile.createNewFile(); + mainConfig=new MainConfig(); + writeMainConfigToFile(mainConfigLocation); + return mainConfig; + } + InputStream inputStream=new FileInputStream(configFile); + ConfigJSON=IOUtils.toString(inputStream, StandardCharsets.UTF_8); + + mainConfig=gson.fromJson(ConfigJSON,MainConfig.class); + + if (mainConfig == null) { + mainConfig=new MainConfig(); + writeMainConfigToFile(mainConfigLocation); + return mainConfig; + } + + }catch (Exception e){ + log.error("Error to load config file:"+e+"\nUse Default config."); + + mainConfig=new MainConfig(); + writeMainConfigToFile(mainConfigLocation); + return mainConfig; + } + + return this.mainConfig; + } + + public VoiceConfig readVoiceConfigFromFile(String fileLocation){ + + //property属性应该要自定义一个json适配器才能解析出来 + Gson gson=new GsonBuilder() + .registerTypeAdapter(SimpleBooleanProperty.class,new BooleanPropertyAdapter()) + .registerTypeAdapter(SimpleIntegerProperty.class,new IntegerPropertyAdapter()) + .registerTypeAdapter(SimpleStringProperty.class,new StringPropertyAdapter()) + .registerTypeAdapter(SimpleDoubleProperty.class,new DoublePropertyAdapter()) + .setPrettyPrinting() + .create(); + + String ConfigJSON; + + try{ + File configFile=new File(fileLocation); + if(!configFile.exists()){ + configFile.getParentFile().mkdirs(); + configFile.createNewFile(); + + voiceConfig=new VoiceConfig(); + writeVoiceConfigToFile(voiceConfigLocation); + return voiceConfig; + } + InputStream inputStream=new FileInputStream(configFile); + ConfigJSON=IOUtils.toString(inputStream, StandardCharsets.UTF_8); + + writeVoiceConfigToFile(voiceConfigLocation); + voiceConfig=gson.fromJson(ConfigJSON,VoiceConfig.class); + if (voiceConfig == null) { + voiceConfig=new VoiceConfig(); + writeVoiceConfigToFile(voiceConfigLocation); + return voiceConfig; + } + + }catch (Exception e){ + log.error("Error to load voice config file:"+e+"\nUse Default voice config."); + + voiceConfig=new VoiceConfig(); + writeVoiceConfigToFile(voiceConfigLocation); + return voiceConfig; + } + + return this.voiceConfig; + } + + // + public MainConfig setValuesToProperty(){ + //mainconfig.set..(config.get..) + //...so on + // + return this.mainConfig; + } + + private String toJSON(MainConfig config){ + + Gson gson=new GsonBuilder() + .registerTypeAdapter(SimpleBooleanProperty.class,new BooleanPropertyAdapter()) + .registerTypeAdapter(SimpleIntegerProperty.class,new IntegerPropertyAdapter()) + .registerTypeAdapter(SimpleStringProperty.class,new StringPropertyAdapter()) + .setPrettyPrinting() + .create(); + + return gson.toJson(config); + } + + private String VoiceConfigtoJSON(VoiceConfig config){ + + Gson gson=new GsonBuilder() + .registerTypeAdapter(SimpleDoubleProperty.class,new DoublePropertyAdapter()) + .setPrettyPrinting() + .create(); + + return gson.toJson(config); + } + + public void writeAllConfigToFile(String outputLocation, String voiceConfigFile){ + File outputFile = new File(outputLocation); + + try{ + if(! outputFile.exists()){ + outputFile.getParentFile().mkdirs(); + outputFile.createNewFile(); + } + OutputStream stream=new FileOutputStream(outputFile); + IOUtils.write(toJSON(this.mainConfig).getBytes(StandardCharsets.UTF_8),stream); + + OutputStream voiceConfigFileStream=new FileOutputStream(voiceConfigFile); + IOUtils.write(VoiceConfigtoJSON(this.voiceConfig).getBytes(StandardCharsets.UTF_8),voiceConfigFileStream); + + }catch (Exception e){ + log.error("Error in writing all config:"+e); + } + } + + public void writeMainConfigToFile(String outputLocation){ + File outputFile = new File(outputLocation); + + try{ + if(! outputFile.exists()){ + outputFile.getParentFile().mkdirs(); + outputFile.createNewFile(); + } + + OutputStream stream=new FileOutputStream(outputFile); + IOUtils.write(toJSON(this.mainConfig).getBytes(StandardCharsets.UTF_8),stream); + + }catch (Exception e){ + log.error("Error in writing main config:"+e); + } + } + + public void writeVoiceConfigToFile(String voiceConfigFile){ + File outputFile = new File(voiceConfigFile); + + try{ + + if(! outputFile.exists()) { + outputFile.getParentFile().mkdirs(); + outputFile.createNewFile(); + } + OutputStream voiceConfigFileStream=new FileOutputStream(voiceConfigFile); + IOUtils.write(VoiceConfigtoJSON(this.voiceConfig).getBytes(StandardCharsets.UTF_8),voiceConfigFileStream); + + }catch (Exception e){ + log.error("Error in writing voice config:"+e); + } + } + +} diff --git a/src/main/java/me/lensferno/dogename/configs/ConfigValuesBean.java b/src/main/java/me/lensferno/dogename/configs/ConfigValuesBean.java new file mode 100644 index 0000000..b5aa7aa --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/ConfigValuesBean.java @@ -0,0 +1,4 @@ +package me.lensferno.dogename.configs; + +public class ConfigValuesBean { +} diff --git a/src/main/java/me/lensferno/dogename/configs/MainConfig.java b/src/main/java/me/lensferno/dogename/configs/MainConfig.java new file mode 100644 index 0000000..ea56552 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/MainConfig.java @@ -0,0 +1,242 @@ +package me.lensferno.dogename.configs; + +import com.google.gson.annotations.Expose; +import javafx.beans.property.*; + +public class MainConfig { + + // ConfigValuesBean configValuesBean =new ConfigValuesBean(); + + // ---------------------- Default values --------------------------------------------------------- + + @Expose + private final String NEWEST_CONFIG_VERSION = "2"; + + private String currentConfigVersion = null; + + @Expose + public final boolean DEFAULT_NAME_CHOOSE = true; + + public final int METHOD_NAME = 0; // 名字挑选法 + public final int METHOD_NUMBER = 1; // 数字挑选法 + + public final int DEFAULT_CYCLE_TIMES = 120; // 默认轮回次数:120 + public final int DEFAULT_SPEED = 80; // 默认速度:20ms,对应滑动条80的位置 + + public final boolean DEFAULT_RANDOM_TIMES = true; // 默认挑选轮回次数是否随机:ture + + public final boolean DEFAULT_IGNORE_PAST = true; // 默认忽略已经点过的名字:ture + + public final boolean DEFAULT_EQUAL_MODE = true; // 默认开启"机会均等" + + public final boolean DEFAULT_NEW_ALGO = true; // 默认使用新算法"Java sec random" + public final boolean DEFAULT_VOICE_PLAY = true; // 默认使用语音播报 + + public final boolean DEFAULT_SHOW_SAYING = true; + + // ----------------------Properties---------------------------------------------------------------- + + private SimpleBooleanProperty nameChooseProperty; + + private SimpleBooleanProperty randomTimesProperty; // 挑选次数是否随机 + private SimpleBooleanProperty ignorePastProperty; // 是否忽略已经被点过的名字 + + private SimpleIntegerProperty chooseMethodProperty; // 挑选方式: 0->名字挑选法 1->数字挑选法 + private SimpleIntegerProperty cycleTimesProperty; // 挑选轮回次数,旧称"chosenTime" + + private SimpleIntegerProperty speedProperty; // 速度 + + private SimpleStringProperty minNumberProperty; // 最小值 + private SimpleStringProperty maxNumberProperty; // 最大值 + + private SimpleBooleanProperty equalModeProperty; // 是否开启"机会均等" + + private SimpleBooleanProperty newAlgoProperty; // 是否使用新算法 + private SimpleBooleanProperty voicePlayProperty; // 是否使用语音播报 + + private SimpleBooleanProperty showSaying; + + // -------------------------- 初始化 -------------------------------------------------------------- + public MainConfig() { + randomTimesProperty = new SimpleBooleanProperty(DEFAULT_RANDOM_TIMES); + ignorePastProperty = new SimpleBooleanProperty(DEFAULT_IGNORE_PAST); + + chooseMethodProperty = new SimpleIntegerProperty(METHOD_NAME); + nameChooseProperty = new SimpleBooleanProperty(DEFAULT_NAME_CHOOSE); + + cycleTimesProperty = new SimpleIntegerProperty(DEFAULT_CYCLE_TIMES); + + speedProperty = new SimpleIntegerProperty(DEFAULT_SPEED); + + minNumberProperty = new SimpleStringProperty("0"); + maxNumberProperty = new SimpleStringProperty("10"); + + equalModeProperty = new SimpleBooleanProperty(DEFAULT_EQUAL_MODE); + + newAlgoProperty = new SimpleBooleanProperty(DEFAULT_NEW_ALGO); + voicePlayProperty = new SimpleBooleanProperty(DEFAULT_VOICE_PLAY); + + showSaying = new SimpleBooleanProperty(DEFAULT_SHOW_SAYING); + + currentConfigVersion = NEWEST_CONFIG_VERSION; + } + + // -------------------------- Getters and Setters --------------------------------------------- + + public boolean isNameChooseProperty() { + return nameChooseProperty.get(); + } + + public SimpleBooleanProperty nameChoosePropertyProperty() { + return nameChooseProperty; + } + + public void setNameChooseProperty(boolean nameChooseProperty) { + this.nameChooseProperty.set(nameChooseProperty); + } + + public boolean isRandomTimesProperty() { + return randomTimesProperty.get(); + } + + public SimpleBooleanProperty randomTimesPropertyProperty() { + return randomTimesProperty; + } + + public void setRandomTimesProperty(boolean randomTimesProperty) { + this.randomTimesProperty.set(randomTimesProperty); + } + + public boolean isIgnorePastProperty() { + return ignorePastProperty.get(); + } + + public SimpleBooleanProperty ignorePastPropertyProperty() { + return ignorePastProperty; + } + + public void setIgnorePastProperty(boolean ignorePastProperty) { + this.ignorePastProperty.set(ignorePastProperty); + } + + public int getChooseMethodProperty() { + return chooseMethodProperty.get(); + } + + public SimpleIntegerProperty chooseMethodPropertyProperty() { + return chooseMethodProperty; + } + + public void setChooseMethodProperty(int chooseMethodProperty) { + this.chooseMethodProperty.set(chooseMethodProperty); + } + + public int getCycleTimesProperty() { + return cycleTimesProperty.get(); + } + + public SimpleIntegerProperty cycleTimesPropertyProperty() { + return cycleTimesProperty; + } + + public void setCycleTimesProperty(int cycleTimesProperty) { + this.cycleTimesProperty.set(cycleTimesProperty); + } + + public int getSpeedProperty() { + return speedProperty.get(); + } + + public SimpleIntegerProperty speedPropertyProperty() { + return speedProperty; + } + + public void setSpeedProperty(int speedProperty) { + this.speedProperty.set(speedProperty); + } + + public String getMinNumberProperty() { + return minNumberProperty.get(); + } + + public SimpleStringProperty minNumberPropertyProperty() { + return minNumberProperty; + } + + public void setMinNumberProperty(String minNumberProperty) { + this.minNumberProperty.set(minNumberProperty); + } + + public String getMaxNumberProperty() { + return maxNumberProperty.get(); + } + + public SimpleStringProperty maxNumberPropertyProperty() { + return maxNumberProperty; + } + + public void setMaxNumberProperty(String maxNumberProperty) { + this.maxNumberProperty.set(maxNumberProperty); + } + + public boolean isEqualModeProperty() { + return equalModeProperty.get(); + } + + public SimpleBooleanProperty equalModePropertyProperty() { + return equalModeProperty; + } + + public void setEqualModeProperty(boolean equalModeProperty) { + this.equalModeProperty.set(equalModeProperty); + } + + public boolean isNewAlgoProperty() { + return newAlgoProperty.get(); + } + + public SimpleBooleanProperty newAlgoPropertyProperty() { + return newAlgoProperty; + } + + public void setNewAlgoProperty(boolean newAlgoProperty) { + this.newAlgoProperty.set(newAlgoProperty); + } + + public boolean isVoicePlayProperty() { + return voicePlayProperty.get(); + } + + public SimpleBooleanProperty voicePlayPropertyProperty() { + return voicePlayProperty; + } + + public void setVoicePlayProperty(boolean voicePlayProperty) { + this.voicePlayProperty.set(voicePlayProperty); + } + + public boolean isShowSaying() { + return showSaying.get(); + } + + public SimpleBooleanProperty showSayingProperty() { + return showSaying; + } + + public void setShowSaying(boolean showSaying) { + this.showSaying.set(showSaying); + } + + public String getCurrentConfigVersion() { + return currentConfigVersion; + } + + public void setCurrentConfigVersion(String currentConfigVersion) { + this.currentConfigVersion = currentConfigVersion; + } + + public String getNewestConfigVersion() { + return NEWEST_CONFIG_VERSION; + } + +} diff --git a/src/main/java/me/lensferno/dogename/configs/VoiceConfig.java b/src/main/java/me/lensferno/dogename/configs/VoiceConfig.java new file mode 100644 index 0000000..aa4be98 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/VoiceConfig.java @@ -0,0 +1,75 @@ +package me.lensferno.dogename.configs; + +import javafx.beans.property.SimpleDoubleProperty; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; + +public class VoiceConfig { + + private String speaker; + private int selectedSpeaker; + + + //度小宇=1,度小美=0,度逍遥=3,度丫丫=4 + //度博文=106,度小童=110,度小萌=111,度米朵=103,度小娇=5 + + private SimpleDoubleProperty speed; + private SimpleDoubleProperty intonation; + + public String getSpeaker() { + return speaker; + } + + public void setSpeaker(String speaker) { + this.speaker = speaker; + } + + public final int DEFAULT_SPEED=5; + public final int DEFAULT_INTONATION=5; + + public VoiceConfig(){ + selectedSpeaker=0; + speaker="1"; + speed=new SimpleDoubleProperty(DEFAULT_SPEED); + intonation=new SimpleDoubleProperty(DEFAULT_INTONATION); + } + + public int getSelectedSpeaker() { + return selectedSpeaker; + } + + public void setSelectedSpeaker(int selectedSpeaker) { + this.selectedSpeaker = selectedSpeaker; + } + public double getSpeed() { + return speed.get(); + } + + public SimpleDoubleProperty speedProperty() { + return speed; + } + + public void setSpeed(double speed) { + this.speed.set(speed); + } + + public double getIntonation() { + return intonation.get(); + } + + public SimpleDoubleProperty intonationProperty() { + return intonation; + } + + public void setIntonation(double intonation) { + this.intonation.set(intonation); + } + + @FXML + void showAdvancedVoiceSettings(ActionEvent event) { + + } + + + +} diff --git a/src/main/java/me/lensferno/dogename/configs/adapters/BooleanPropertyAdapter.java b/src/main/java/me/lensferno/dogename/configs/adapters/BooleanPropertyAdapter.java new file mode 100644 index 0000000..6c87d4a --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/adapters/BooleanPropertyAdapter.java @@ -0,0 +1,27 @@ +package me.lensferno.dogename.configs.adapters; + +import com.google.gson.*; +import javafx.beans.property.SimpleBooleanProperty; + +import java.lang.reflect.Type; + +public class BooleanPropertyAdapter implements JsonSerializer, JsonDeserializer { + + @Override + public SimpleBooleanProperty deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + if(jsonElement==null) { + throw new JsonParseException("Json is wrong."); + }else { + return new SimpleBooleanProperty(jsonElement.getAsBoolean()); + } + } + + @Override + public JsonElement serialize(SimpleBooleanProperty simpleBooleanProperty, Type type, JsonSerializationContext jsonSerializationContext) { + if(simpleBooleanProperty==null){ + throw new JsonParseException("Json is wrong."); + }else { + return new JsonPrimitive(simpleBooleanProperty.get()); + } + } +} diff --git a/src/main/java/me/lensferno/dogename/configs/adapters/DoublePropertyAdapter.java b/src/main/java/me/lensferno/dogename/configs/adapters/DoublePropertyAdapter.java new file mode 100644 index 0000000..7038884 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/adapters/DoublePropertyAdapter.java @@ -0,0 +1,27 @@ +package me.lensferno.dogename.configs.adapters; + +import com.google.gson.*; +import javafx.beans.property.SimpleDoubleProperty; + +import java.lang.reflect.Type; + +public class DoublePropertyAdapter implements JsonSerializer, JsonDeserializer { + + @Override + public SimpleDoubleProperty deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + if(jsonElement==null) { + throw new JsonParseException("Json is wrong."); + }else { + return new SimpleDoubleProperty(jsonElement.getAsDouble()); + } + } + + @Override + public JsonElement serialize(SimpleDoubleProperty simpleDoubleProperty, Type type, JsonSerializationContext jsonSerializationContext) { + if(simpleDoubleProperty==null){ + throw new JsonParseException("Json is wrong."); + }else { + return new JsonPrimitive(simpleDoubleProperty.get()); + } + } +} diff --git a/src/main/java/me/lensferno/dogename/configs/adapters/IntegerPropertyAdapter.java b/src/main/java/me/lensferno/dogename/configs/adapters/IntegerPropertyAdapter.java new file mode 100644 index 0000000..3ee6351 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/adapters/IntegerPropertyAdapter.java @@ -0,0 +1,26 @@ +package me.lensferno.dogename.configs.adapters; + +import com.google.gson.*; +import javafx.beans.property.SimpleIntegerProperty; + +import java.lang.reflect.Type; + +public class IntegerPropertyAdapter implements JsonSerializer, JsonDeserializer { + @Override + public SimpleIntegerProperty deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + if(jsonElement==null) { + throw new JsonParseException("Json is wrong."); + }else { + return new SimpleIntegerProperty(jsonElement.getAsInt()); + } + } + + @Override + public JsonElement serialize(SimpleIntegerProperty simpleIntegerProperty, Type type, JsonSerializationContext jsonSerializationContext) { + if(simpleIntegerProperty==null){ + throw new JsonParseException("Json is wrong."); + }else { + return new JsonPrimitive(simpleIntegerProperty.get()); + } + } +} diff --git a/src/main/java/me/lensferno/dogename/configs/adapters/StringPropertyAdapter.java b/src/main/java/me/lensferno/dogename/configs/adapters/StringPropertyAdapter.java new file mode 100644 index 0000000..0bbf7d5 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/configs/adapters/StringPropertyAdapter.java @@ -0,0 +1,26 @@ +package me.lensferno.dogename.configs.adapters; + +import com.google.gson.*; +import javafx.beans.property.SimpleStringProperty; + +import java.lang.reflect.Type; + +public class StringPropertyAdapter implements JsonSerializer, JsonDeserializer { + @Override + public SimpleStringProperty deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + if(jsonElement==null) { + throw new JsonParseException("Json is wrong."); + }else { + return new SimpleStringProperty(jsonElement.getAsString()); + } + } + + @Override + public JsonElement serialize(SimpleStringProperty simpleStringProperty, Type type, JsonSerializationContext jsonSerializationContext) { + if(simpleStringProperty==null) { + throw new JsonParseException("Json is wrong."); + }else { + return new JsonPrimitive(simpleStringProperty.get()); + } + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/GushiciPaneController.java b/src/main/java/me/lensferno/dogename/controllers/GushiciPaneController.java new file mode 100644 index 0000000..de2e948 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/GushiciPaneController.java @@ -0,0 +1,39 @@ +package me.lensferno.dogename.controllers; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + + +public class GushiciPaneController extends VBox { + + Logger log= LogManager.getLogger(); + @FXML + public Text contentText; + + @FXML + public Text contentType; + + @FXML + public Text contentInfo; + + public GushiciPaneController (String content,String title,String author,String type){ + + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/GushiciPane.fxml")); + loader.setRoot(this); + loader.setController(this); + try { + loader.load(); + }catch(Exception e){ + log.error("Error to load Gushici pane FXML: "+e.toString()); + + //e.printStackTrace(); + } + contentText.setText("“"+content+"”"); + contentInfo.setText("《"+title+"》"+"——"+author); + contentType.setText(type); + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/HistoryPaneController.java b/src/main/java/me/lensferno/dogename/controllers/HistoryPaneController.java new file mode 100644 index 0000000..d1a0328 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/HistoryPaneController.java @@ -0,0 +1,126 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.*; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; +import me.lensferno.dogename.utils.DialogMaker; +import me.lensferno.dogename.data.History; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class HistoryPaneController extends VBox { + Logger log= LogManager.getLogger(HitokotoPaneController.class); + + History history; + Pane rootPane; + + public static final ObservableList shownHistoryList = FXCollections.observableArrayList(); + + public HistoryPaneController(History history, Pane rootPane){ + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/HistoryPane.fxml")); + loader.setRoot(this); + loader.setController(this); + this.history=history; + this.rootPane=rootPane; + + try { + loader.load(); + shownHistoryList.setAll(history.getHistoryList()); + historyList.setItems(shownHistoryList); + searchBar.textProperty().addListener((observable, oldValue, newValue) -> pointer = 0); + + }catch(Exception e){ + log.error("Error in loading history Fxml:"+e.toString()); + } + } + + @FXML + private JFXListView historyList; + + @FXML + private JFXTextField searchBar; + + @FXML + private JFXButton previousBtn; + + @FXML + private JFXButton nextBtn; + + private void pointOutSearchResult(int pointer){ + historyList.getSelectionModel().select(pointer); + } + + int pointer=0; + + @FXML + void upSearch(ActionEvent event) { + + String searchText=searchBar.getText(); + String[] historyArrayList =history.getHistoryList().toArray(new String[0]); + + if (historyArrayList.length==0){ + return; + } + + if (pointer>historyArrayList.length-1||pointer<0){ + pointer=historyArrayList.length-1; + } + + while (!historyArrayList[pointer].contains(searchText)){ + pointer--; + if (pointer<0){ + pointer=historyArrayList.length-1; + return; + } + } + pointOutSearchResult(pointer); + pointer--; + if (pointer<0){ + pointer=historyArrayList.length-1; + } + + } + + @FXML + void downSearch(ActionEvent event) { + + String searchText=searchBar.getText(); + String[] historyArrayList =history.getHistoryList().toArray(new String[0]); + + if (historyArrayList.length==0){ + return; + } + + if (pointer>historyArrayList.length-1||pointer<0){ + pointer=0; + } + + while (!historyArrayList[pointer].contains(searchText)){ + pointer++; + if (pointer { + this.history.clearHistory(); + pointer=0; + }); + } + +} diff --git a/src/main/java/me/lensferno/dogename/controllers/HitokotoPaneController.java b/src/main/java/me/lensferno/dogename/controllers/HitokotoPaneController.java new file mode 100644 index 0000000..7f97b2b --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/HitokotoPaneController.java @@ -0,0 +1,38 @@ +package me.lensferno.dogename.controllers; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; + +import java.util.logging.Logger; + +public class HitokotoPaneController extends VBox { + + Logger log=Logger.getLogger("HitokotoPaneLogger"); + + @FXML + private Text hitokotoContent; + + @FXML + private Text contentType; + + @FXML + private Text contentInfo; + + public HitokotoPaneController(String hitokoto, String from,String author,String creator,String type){ + + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/HitokotoPane.fxml")); + loader.setRoot(this); + loader.setController(this); + try { + loader.load(); + }catch(Exception e){ + log.warning("Error to load Gushici pane FXML: "+e.toString()); + //e.printStackTrace(); + } + hitokotoContent.setText("『 "+hitokoto+" 』"); + contentInfo.setText("出自:"+from+"  |  作者:"+author+"  |  上传者:"+creator); + contentType.setText(type); + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/MainInterfaceController.java b/src/main/java/me/lensferno/dogename/controllers/MainInterfaceController.java new file mode 100644 index 0000000..2ac503a --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/MainInterfaceController.java @@ -0,0 +1,337 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.*; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; +import javafx.stage.StageStyle; +import me.lensferno.dogename.utils.DialogMaker; +import me.lensferno.dogename.choose.Chooser; +import me.lensferno.dogename.configs.ConfigLoader; +import me.lensferno.dogename.configs.MainConfig; +import me.lensferno.dogename.configs.VoiceConfig; +import me.lensferno.dogename.data.History; +import me.lensferno.dogename.data.NameData; +import me.lensferno.dogename.ocr.Ocr; +import me.lensferno.dogename.voice.Token; +import me.lensferno.dogename.voice.TokenManager; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashSet; +import java.util.Random; + +public final class MainInterfaceController { + + public JFXTextArea message; + + //ConfigLoader configLoader=new ConfigLoader(); + + Token token; + TokenManager tokenManager=new TokenManager(); + + Ocr ocrTool=null; + + History history=new History(); + + @FXML + private Pane rootPane; + + @FXML + private JFXRadioButton nameChoose; + + @FXML + private JFXButton showHistoryBtn; + + @FXML + private JFXRadioButton numbChoose; + + @FXML + private JFXButton anPaiBtn; + + @FXML + private JFXButton anPaiX10Btn; + + @FXML + private Pane mainPane; + + @FXML + private Label topBar; + + @FXML + private JFXButton showNameMangerButton; + + @FXML + private Label chosen_1; + + @FXML + private ImageView mainView; + + @FXML + private JFXButton miniModeBtn; + + @FXML + private Label chosen_2; + + public MainInterfaceController(){ + history.loadHistory(); + nameData.readIgnoreList(); + tokenManager.init(); + this.ignoreNameList=nameData.getIgnoreNameList(); + this.ignoreNumberList=nameData.getIgnoreNumberList(); + if(tokenManager.getTokenStatus().equals("ok")){ + token=tokenManager.getToken(); + } + } + + MainConfig mainConfig; + VoiceConfig voiceConfig; + + public void bindProperties(){ + nameChoose.selectedProperty().bindBidirectional(mainConfig.nameChoosePropertyProperty()); + //mainConfig.nameChoosePropertyProperty().not() + + numbChoose.selectedProperty().bind(mainConfig.nameChoosePropertyProperty().not()); + numbChoose.selectedProperty().unbind(); + +/* + mainConfig.nameChoosePropertyProperty().addListener((observable, oldValue, newValue) -> { + //numbChoose.selectedProperty().unbind(); + numbChoose.setSelected(oldValue); + });*/ + + } + + public void setImg(InputStream stream){ + mainView.setImage(new Image(stream)); + } + + public void setUpConfig(ConfigLoader configLoader){ + mainConfig=configLoader.readConfigFromFile("files"+ File.separator +"Config.json"); + voiceConfig=configLoader.readVoiceConfigFromFile("files"+ File.separator +"VoiceConfig.json"); + } + + @FXML + void showProgramInfo(ActionEvent event) { + new DialogMaker(rootPane).createDialogWithOneBtn("程序信息",new ProgramInfoPaneController(rootPane)); + } + + + @FXML + void showNameManger(ActionEvent event) { + + if (chooser.isRunning()){ + new DialogMaker(rootPane).createMessageDialog("(・。・)","安排中......\n为保证运行的稳定,此时还不能进行该操作哦。"); + return; + } + NameManagerPaneController nameManagerPaneController =new NameManagerPaneController(nameData,rootPane,ocrTool); + new DialogMaker(rootPane).createDialogWithOneBtn("名单管理",nameManagerPaneController); + } + + + + @FXML + void showNunberSetting(ActionEvent event) { + + if (chooser.isRunning()){ + new DialogMaker(rootPane).createMessageDialog("(・。・)","安排中......\n为保证运行的稳定,此时还不能进行该操作哦。"); + return; + } + NumberSettingsPaneController numberSettingsPaneController =new NumberSettingsPaneController(nameData); + numberSettingsPaneController.bindProperties(mainConfig); + new DialogMaker(rootPane).createDialogWithOneBtn("调整数字",numberSettingsPaneController); + + } + + Logger log= LogManager.getLogger(); + + @FXML + void miniMode(ActionEvent event) { + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/MiniPane.fxml")); + Parent parent; + try { + parent=loader.load(); + } catch (IOException e) { + log.error("Error in loading MiniPane Fxml:"+e); + return; + } + + Scene miniScene=new Scene(parent,300,134); + Stage miniStage=new Stage(); + miniStage.setScene(miniScene); + miniStage.initStyle(StageStyle.UNDECORATED); + + MiniPaneController miniPaneController=loader.getController(); + miniPaneController.setBase(history,nameData,token,voiceConfig,mainConfig); + + Stage currentStage=(Stage)anPaiBtn.getScene().getWindow(); + miniPaneController.setForwStage(currentStage); + + miniPaneController.setCurrentStage(miniStage); + miniPaneController.setCurrentScene(miniScene); + + miniPaneController.setListeners(); + + miniStage.show(); + currentStage.close(); + + } + + @FXML + void showSettings(ActionEvent event) { + + SettingsPaneController settingsPaneController =new SettingsPaneController(); + + settingsPaneController.setToggleGroup(); + settingsPaneController.bindProperties(mainConfig); + + settingsPaneController.setVoiceConfig(voiceConfig); + + settingsPaneController.setRootPane(rootPane); + + settingsPaneController.setNameData(nameData); + + new DialogMaker(rootPane).createDialogWithOneBtn("更多设置",settingsPaneController); + } + + @FXML + void showHistory(ActionEvent event) { + + HistoryPaneController historyPaneController =new HistoryPaneController(history,rootPane); + + new DialogMaker(rootPane).createDialogWithOneBtn("历史记录",historyPaneController); + } + + Random random=new Random(); + + HashSet ignoreNameList; + HashSet ignoreNumberList; + + NameData nameData=new NameData(); + //boolean isRunning=false; + + Chooser chooser=new Chooser(); + + @FXML + void anPai() { + + if(chooser.isRunning()){ + chooser.setForceStop(true); + anPaiBtn.setText("安排一下"); + return; + } + + if(mainConfig.isRandomTimesProperty()) { + mainConfig.setCycleTimesProperty(100+random.nextInt(151)); + } + + if(mainConfig.isNameChooseProperty()){ + runNameMode(chooser); + }else { + runNumberMode(chooser); + } + + } + + + public void setToggleGroup(){ + ToggleGroup toggleGroup =new ToggleGroup(); + nameChoose.setToggleGroup(toggleGroup); + numbChoose.setToggleGroup(toggleGroup); + } + + private void runNameMode(Chooser chooser){ + + if(nameData.isEmpty()){ + new DialogMaker(rootPane).createMessageDialog("哦霍~","现在名单还是空的捏~请前往名单管理添加名字 或 使用数字挑选法。"); + return; + } + + if((nameData.getIgnoreNameList().size()>=nameData.getSize())&&mainConfig.isIgnorePastProperty()){ + + if(mainConfig.isEqualModeProperty()) { + new DialogMaker(rootPane).createDialogWithOKAndCancel("啊?", "全部名字都被点完啦!\n要把名字的忽略列表重置吗?", e ->nameData.clearNameIgnoreList()); + }else { + new DialogMaker(rootPane).createMessageDialog("啊?", "全部名字都被点完啦!\n请多添加几个名字 或 点击“机会均等”的“重置”按钮。"); + } + return; + } + + anPaiBtn.setText("不玩了!"); + + chooser.set(chosen_1.textProperty(),chosen_2.textProperty(),anPaiBtn,history,nameData,token,voiceConfig); + + chooser.run( + (short)(100-mainConfig.getSpeedProperty()) , + mainConfig.getCycleTimesProperty(), + mainConfig.isIgnorePastProperty(), + mainConfig.isEqualModeProperty(), + mainConfig.isVoicePlayProperty() + ); + + } + + + private void runNumberMode(Chooser chooser){ + + try{ + + int minNumber=Integer.parseInt(mainConfig.getMinNumberProperty()); + int maxNumber=Integer.parseInt(mainConfig.getMaxNumberProperty()); + + if(maxNumber-minNumber<=0){ + new DialogMaker(rootPane).createMessageDialog("嗯哼?","数字要前小后大啊~"); + return; + } + + if(nameData.getIgnoreNumberList().size()>=(maxNumber-minNumber+1) && mainConfig.isIgnorePastProperty()){ + if(mainConfig.isEqualModeProperty()) { + new DialogMaker(rootPane).createDialogWithOKAndCancel("啊?", "全部数字都被点完啦!\n要把数字的忽略列表重置吗?", e ->nameData.clearNumberIgnoreList()); + }else { + new DialogMaker(rootPane).createMessageDialog("啊?", "全部数字都被点完啦!\n请扩大数字范围 或 点击“机会均等”的“重置”按钮。"); + } + return; + } + + }catch (Exception e){ + new DialogMaker(rootPane).createMessageDialog("嗯哼?","输入个有效的数字啊~"); + return; + } + + anPaiBtn.setText("不玩了!"); + + chooser.set(chosen_1.textProperty(),chosen_2.textProperty(),anPaiBtn,history,nameData,token,voiceConfig); + + chooser.run( + Short.parseShort(mainConfig.getMaxNumberProperty()), + Short.parseShort(mainConfig.getMinNumberProperty()), + (short)(100-mainConfig.getSpeedProperty()) , + mainConfig.getCycleTimesProperty(), + mainConfig.isIgnorePastProperty(), + mainConfig.isEqualModeProperty(), + mainConfig.isVoicePlayProperty() + ); + } + + public Label getTopBar() { + return topBar; + } + + public Pane getRootPane() { + return rootPane; + } + + public MainConfig getMainConfig() { + return mainConfig; + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/MiniPaneController.java b/src/main/java/me/lensferno/dogename/controllers/MiniPaneController.java new file mode 100644 index 0000000..d8cd9ba --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/MiniPaneController.java @@ -0,0 +1,191 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.JFXButton; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.TouchEvent; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; +import me.lensferno.dogename.utils.DialogMaker; +import me.lensferno.dogename.choose.Chooser; +import me.lensferno.dogename.configs.MainConfig; +import me.lensferno.dogename.configs.VoiceConfig; +import me.lensferno.dogename.controllers.WindowListeners.MoveWindowByMouse; +import me.lensferno.dogename.controllers.WindowListeners.MoveWindowByTouch; +import me.lensferno.dogename.data.History; +import me.lensferno.dogename.data.NameData; +import me.lensferno.dogename.voice.Token; + +import java.util.Random; + +public class MiniPaneController { + + @FXML + private Label chosenNameLabel; + + @FXML + private JFXButton anPaiBtn; + + @FXML + private JFXButton miniModeBtn; + + Stage forwStage; + + public Stage getForwStage() { + return forwStage; + } + + public void setForwStage(Stage forwStage) { + this.forwStage = forwStage; + } + + private Random random=new Random(); + private NameData nameData; + private Pane rootPane; + private History history; + private Token token; + private VoiceConfig voiceConfig; + + Stage currentStage; + Scene currentScene; + + public void setCurrentScene(Scene currentScene) { + this.currentScene = currentScene; + } + + public void setCurrentStage(Stage currentStage) { + this.currentStage = currentStage; + } + + public void setBase(History history, NameData nameData, Token token, VoiceConfig voiceConfig, MainConfig mainConfig){ + + this.history = history; + this.nameData = nameData; + + this.token=token; + + this.voiceConfig=voiceConfig; + + this.mainConfig=mainConfig; + + } + + @FXML + void recoverMode(ActionEvent event) { + this.forwStage.show(); + currentStage.close(); + } + + public void setListeners(){ + EventHandler mouseHandler=new MoveWindowByMouse(currentStage); + chosenNameLabel.setOnMousePressed(mouseHandler); + chosenNameLabel.setOnMouseDragged(mouseHandler); + + EventHandler touchHandler=new MoveWindowByTouch(currentStage); + chosenNameLabel.setOnTouchPressed(touchHandler); + chosenNameLabel.setOnTouchMoved(touchHandler); + + anPaiBtn.setOnMousePressed(mouseHandler); + anPaiBtn.setOnMouseDragged(mouseHandler); + + anPaiBtn.setOnTouchPressed(touchHandler); + anPaiBtn.setOnTouchMoved(touchHandler); + + miniModeBtn.setOnMousePressed(mouseHandler); + miniModeBtn.setOnMouseDragged(mouseHandler); + + miniModeBtn.setOnTouchPressed(touchHandler); + miniModeBtn.setOnTouchMoved(touchHandler); + } + + + + private MainConfig mainConfig; + Chooser chooser=new Chooser(); + + @FXML + void anPai() { + if(chooser.isRunning()){ + chooser.setForceStop(true); + anPaiBtn.setText("安排一下"); + return; + } + + if(mainConfig.isRandomTimesProperty()) { + mainConfig.setCycleTimesProperty(100+random.nextInt(151)); + } + + if(mainConfig.isNameChooseProperty()){ + runNameMode(chooser); + }else { + runNumberMode(chooser); + } + + } + + + private void runNameMode(Chooser chooser){ + + if(nameData.isEmpty()){ + return; + } + + if((nameData.getIgnoreNameList().size()>=nameData.getSize())&&mainConfig.isIgnorePastProperty()){ + + return; + } + + anPaiBtn.setText("不玩了!"); + + chooser.set(chosenNameLabel.textProperty(),chosenNameLabel.textProperty(),anPaiBtn,history,nameData,token,voiceConfig); + + chooser.run( + (short)(100-mainConfig.getSpeedProperty()) , + mainConfig.getCycleTimesProperty(), + mainConfig.isIgnorePastProperty(), + mainConfig.isEqualModeProperty(), + mainConfig.isVoicePlayProperty() + ); + + } + + + private void runNumberMode(Chooser chooser){ + + try{ + + int minNumber=Integer.parseInt(mainConfig.getMinNumberProperty()); + int maxNumber=Integer.parseInt(mainConfig.getMaxNumberProperty()); + + if(maxNumber-minNumber<=0){ + return; + } + + if(nameData.getIgnoreNumberList().size()>=(maxNumber-minNumber+1) && mainConfig.isIgnorePastProperty()){ + return; + } + + }catch (Exception e){ + new DialogMaker(rootPane).createMessageDialog("嗯哼?","倒是输入个有效的数字啊~"); + return; + } + + anPaiBtn.setText("不玩了!"); + + chooser.set(chosenNameLabel.textProperty(),chosenNameLabel.textProperty(),anPaiBtn,history,nameData,token,voiceConfig); + + chooser.run( + Short.parseShort(mainConfig.getMaxNumberProperty()), + Short.parseShort(mainConfig.getMinNumberProperty()), + (short)(100-mainConfig.getSpeedProperty()) , + mainConfig.getCycleTimesProperty(), + mainConfig.isIgnorePastProperty(), + mainConfig.isEqualModeProperty(), + mainConfig.isVoicePlayProperty() + ); + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/NameManagerPaneController.java b/src/main/java/me/lensferno/dogename/controllers/NameManagerPaneController.java new file mode 100644 index 0000000..443496f --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/NameManagerPaneController.java @@ -0,0 +1,191 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.*; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; +import javafx.stage.FileChooser; +import javafx.stage.Stage; +import me.lensferno.dogename.utils.DialogMaker; +import me.lensferno.dogename.data.NameData; +import me.lensferno.dogename.ocr.Ocr; +import me.lensferno.dogename.utils.Clipboard; + +import java.io.File; +import java.util.logging.Logger; + +public class NameManagerPaneController extends VBox { + + NameData nameData; + Pane rootPane; + Ocr ocrTool; + + Logger log = Logger.getLogger("NameManagerPaneLOgger"); + + public static final ObservableList shownNameList = FXCollections.observableArrayList(); + + public NameManagerPaneController(NameData nameData, Pane rootPane, Ocr ocrTool){ + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/NameManagerPane.fxml")); + loader.setRoot(this); + loader.setController(this); + try { + loader.load(); + }catch(Exception e){ + e.printStackTrace(); + } + this.nameData=nameData; + this.rootPane=rootPane; + + shownNameList.setAll(nameData.getNameList()); + this.nameList.setItems(shownNameList); + + this.ocrTool=ocrTool; + } + + @FXML + private JFXListView nameList; + + @FXML + private JFXButton deleteAll; + + @FXML + private JFXButton addName; + + @FXML + private JFXButton deleteName; + + @FXML + private JFXTextArea inputName; + + + @FXML + void deleteName(ActionEvent event) { + + new DialogMaker(rootPane).createDialogWithOKAndCancel( + "问一下", + "真的要这个名字吗?该操作无法撤销,除非您已经备份了名单。", + e -> { + String deletedName = nameList.getSelectionModel().getSelectedItems().get(0); + + nameData.delete(deletedName); + shownNameList.remove(deletedName); + + nameData.saveToFile(); + System.gc(); + }); + + } + + @FXML + void deleteAllName(ActionEvent event) { + new DialogMaker(rootPane).createDialogWithOKAndCancel( + "问一下", + "真的要删掉所有名字吗?该操作无法撤销,除非您已经备份了名单。", + e -> { + //delete all name + nameData.deleteAll(); + shownNameList.setAll(nameData.getNameList()); + nameData.saveToFile(); + }); + + } + + @FXML + void makeMass(ActionEvent event) { + nameData.makeMass(); + shownNameList.clear(); + shownNameList.setAll(nameData.getNameList()); + nameData.saveToFile(); + } + + @FXML + void exoprtNameList(ActionEvent event) { + FileChooser fileChooser = new FileChooser(); + fileChooser.setInitialFileName("nameList.txt"); + fileChooser.setTitle("想保存到哪?"); + File file = fileChooser.showSaveDialog(rootPane.getScene().getWindow()); + nameData.exportNameList(file); + System.gc(); + } + + @FXML + void importNameList(ActionEvent event) { + + new DialogMaker(rootPane).createDialogWithOKAndCancel( + "问一下", + "导入恢复名单会覆盖当前已有的名单,是否继续?", + event1 -> { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("告诉我在哪?"); + File file = fileChooser.showOpenDialog(rootPane.getScene().getWindow()); + + nameData.importNameList(file); + shownNameList.clear(); + shownNameList.setAll(nameData.getNameList()); + + nameData.clearNameIgnoreList(); + nameData.clearNumberIgnoreList(); + + nameData.saveToFile(); + System.gc(); + }); + + } + + @FXML + void addName(ActionEvent event) { + + if(inputName.getText().equals("")){ + new DialogMaker(rootPane).createMessageDialog("诶诶诶~","输入框怎么是空的呢?"); + return; + } + + nameData.add(inputName.getText()); + + shownNameList.clear(); + shownNameList.setAll(nameData.getNameList()); + + nameData.saveToFile(); + inputName.clear(); + System.gc(); + } + + @FXML + void addNameFromScreen(ActionEvent event) { + FXMLLoader fxmlLoader; + Parent parent; + + Stage stage=new Stage(); + + try{ + fxmlLoader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/OcrPane.fxml")); + parent=fxmlLoader.load(); + }catch (Exception e){ + log.warning("Error to load main interface FXML :"+e.toString()); + return; + } + + Scene scene=new Scene(parent,515,604); + stage.setTitle("Ocr模块"); + stage.setScene(scene); + log.fine("窗口加载完成"); + + OcrPaneController ocrPaneController= fxmlLoader.getController(); + ocrPaneController.setpStage((Stage)inputName.getScene().getWindow()); + stage.show(); + + } + + @FXML + void copyTo(ActionEvent event) { + inputName.setText(inputName.getText()+ Clipboard.getClipboardString()); + } + + +} diff --git a/src/main/java/me/lensferno/dogename/controllers/NumberSettingsPaneController.java b/src/main/java/me/lensferno/dogename/controllers/NumberSettingsPaneController.java new file mode 100644 index 0000000..128b3b6 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/NumberSettingsPaneController.java @@ -0,0 +1,39 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.JFXTextField; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.layout.VBox; +import me.lensferno.dogename.configs.MainConfig; +import me.lensferno.dogename.data.NameData; + +public class NumberSettingsPaneController extends VBox { + NameData nameData; + public NumberSettingsPaneController(NameData nameData){ + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/NumberSettingPane.fxml")); + loader.setRoot(this); + loader.setController(this); + try { + loader.load(); + }catch(Exception e){ + e.printStackTrace(); + } + this.nameData=nameData; + } + + @FXML + private JFXTextField minValueField; + + @FXML + private JFXTextField maxValueField; + + public void bindProperties(MainConfig mainConfig){ + + minValueField.textProperty().bindBidirectional(mainConfig.minNumberPropertyProperty()); + minValueField.textProperty().addListener((observable, oldValue, newValue) -> nameData.clearNumberIgnoreList() ); + + maxValueField.textProperty().bindBidirectional(mainConfig.maxNumberPropertyProperty()); + maxValueField.textProperty().addListener((observable, oldValue, newValue) -> nameData.clearNumberIgnoreList() ); + } + +} diff --git a/src/main/java/me/lensferno/dogename/controllers/OcrPaneController.java b/src/main/java/me/lensferno/dogename/controllers/OcrPaneController.java new file mode 100644 index 0000000..e4a05e0 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/OcrPaneController.java @@ -0,0 +1,93 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.JFXSpinner; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.TextArea; +import javafx.scene.text.Text; +import javafx.stage.Stage; +import me.lensferno.dogename.ocr.Ocr; +import me.lensferno.dogename.ocr.ScreenCapture; +import me.lensferno.dogename.utils.Clipboard; + +public class OcrPaneController { + + Ocr ocr; + + @FXML + private TextArea ocrText; + + @FXML + private Text statusText; + + @FXML + private JFXSpinner loadingSpinner; + + Stage pStage; + + public void setpStage(Stage pStage) { + this.pStage = pStage; + } + + @FXML + void addNew(ActionEvent event) { + + Stage stage=(Stage)ocrText.getScene().getWindow(); + stage.hide(); + pStage.hide(); + + //等待系统动画结束 + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + boolean captureSuccess= ScreenCapture.getScreenCapture(); + + if(!captureSuccess){ + statusText.setText("状态:截屏失败。"); + System.out.println("状态:截屏失败。"); + pStage.show(); + stage.show(); + return; + } + loadingSpinner.setVisible(true); + + if(ocr==null){ + ocr=new Ocr(); + ocr.init(); + } + + new Thread(()->{ + boolean ocrSuccrss=ocr.identifyPrecisely(ScreenCapture.SCREEN_CAPTURE_LOCA); + + if (ocrSuccrss) { + + Platform.runLater(()->{ + ocrText.setText(ocrText.getText()+ocr.getResult()); + statusText.setText("状态:成功。"); + System.out.println("状态:成功。"); + loadingSpinner.setVisible(false); + + }); + }else { + Platform.runLater(()->{ + ocrText.setText(ocr.getResult()); + statusText.setText("状态:失败。"); + System.out.println("状态:失败。"); + loadingSpinner.setVisible(false); + + }); + } + }).start(); + pStage.show(); + stage.show(); + } + + @FXML + void copyText(ActionEvent event) { + Clipboard.copyToClipboard(ocrText.getText()); + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/ProgramInfoPaneController.java b/src/main/java/me/lensferno/dogename/controllers/ProgramInfoPaneController.java new file mode 100644 index 0000000..0e399d7 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/ProgramInfoPaneController.java @@ -0,0 +1,137 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.JFXButton; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.TextArea; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import javafx.scene.text.Text; +import me.lensferno.dogename.DataReleaser; +import me.lensferno.dogename.utils.DialogMaker; +import me.lensferno.dogename.resources.LicenseText; + +import java.awt.*; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +public class ProgramInfoPaneController extends VBox { + + @FXML + public ImageView dogeView; + + Pane rootPane; + + public ProgramInfoPaneController(Pane rootPane){ + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/ProgramInfoPane.fxml")); + loader.setRoot(this); + loader.setController(this); + try { + loader.load(); + }catch(Exception e){ + e.printStackTrace(); + } + Image dogeImage=new Image(DataReleaser.getDogenameStream()); + dogeView.setImage(dogeImage); + this.rootPane=rootPane; + } + + + @FXML + void showLicense(ActionEvent event) { + TextArea textArea=new TextArea(LicenseText.text); + textArea.setFont(Font.font("Microsoft YaHei",14)); + textArea.setMinWidth(600); + textArea.setPrefHeight(400); + textArea.setEditable(false); + new DialogMaker(rootPane).createDialogWithOneBtn("开源协议(LGPL v3)",textArea); + } + + @FXML + void showLibLicense(ActionEvent event) { + TextArea textArea=new TextArea(LicenseText.libLicense); + textArea.setFont(Font.font("Microsoft YaHei",14)); + textArea.setMinWidth(600); + textArea.setPrefHeight(400); + textArea.setEditable(false); + new DialogMaker(rootPane).createDialogWithOneBtn("其他开源许可",textArea); + } + + @FXML + void showHelp(ActionEvent event) { + + JFXButton YesButton = new JFXButton("好的~去吧去吧"); + YesButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD,14)); + YesButton.setPrefWidth(160); + YesButton.setPrefHeight(40); + YesButton.addEventHandler(ActionEvent.ACTION,e -> jumpToHelp()); + + JFXButton cancelButton = new JFXButton("算了算了"); + cancelButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD,14)); + cancelButton.setPrefWidth(100); + cancelButton.setPrefHeight(40); + + Text messageText=new Text("即将跳转到本程序Github页面上的使用帮助,是否继续?"); + messageText.setFont(Font.font("Microsoft YaHei",14)); + + new DialogMaker(rootPane).createDialog("查看帮助",messageText,cancelButton,YesButton); + + } + + private void jumpToHelp(){ + try { + Desktop.getDesktop().browse(new URI("https://github.com/lensferno/dogename/blob/main/res/usage.md")); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + } + + @FXML + void viewCode(ActionEvent event) { + JFXButton githubButton = new JFXButton("前往Github查看"); + githubButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD,14)); + githubButton.setPrefWidth(150); + githubButton.setPrefHeight(40); + githubButton.addEventHandler(ActionEvent.ACTION,e -> jumpToGithub()); + + JFXButton giteeButton = new JFXButton("前往Gitee查看"); + giteeButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD,14)); + giteeButton.setPrefWidth(150); + giteeButton.setPrefHeight(40); + giteeButton.addEventHandler(ActionEvent.ACTION,e -> jumpToGitee()); + + JFXButton cancelButton = new JFXButton("哪都不去"); + cancelButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD,14)); + cancelButton.setPrefWidth(100); + cancelButton.setPrefHeight(40); + + Text messageText=new Text("Dogename在Github和码云(Gitee)都发布有代码和介绍。\n您想去哪里?\nGithub:将跳转到https://github.com/lensferno/dogename\nGitee:将跳转到https://gitee.com/lensferno/dogename"); + messageText.setFont(Font.font("Microsoft YaHei",14)); + + new DialogMaker(rootPane).createDialog("查看源代码",messageText,cancelButton,githubButton,giteeButton); + + } + + private void jumpToGithub(){ + try { + Desktop.getDesktop().browse(new URI("https://github.com/lensferno/dogename")); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + } + + private void jumpToGitee(){ + try { + Desktop.getDesktop().browse(new URI("https://gitee.com/lensferno/dogename")); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/me/lensferno/dogename/controllers/SettingsPaneController.java b/src/main/java/me/lensferno/dogename/controllers/SettingsPaneController.java new file mode 100644 index 0000000..8065f8f --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/SettingsPaneController.java @@ -0,0 +1,157 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.JFXCheckBox; +import com.jfoenix.controls.JFXRadioButton; +import com.jfoenix.controls.JFXSlider; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; +import me.lensferno.dogename.utils.DialogMaker; +import me.lensferno.dogename.configs.MainConfig; +import me.lensferno.dogename.configs.VoiceConfig; +import me.lensferno.dogename.data.NameData; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + + +public class SettingsPaneController extends VBox { + + @FXML + private JFXCheckBox showSayingBtn; + + @FXML + private JFXCheckBox newAlgoBtn; + + @FXML + private JFXSlider cycleTimesBar; + + @FXML + private JFXCheckBox voicePlayBtn; + + @FXML + private JFXSlider speedBar; + + @FXML + private JFXCheckBox equalModeBtn; + + @FXML + private JFXRadioButton ignoreOnce; + + @FXML + private JFXRadioButton chooseOnce; + + @FXML + private JFXRadioButton randomTimes; + + @FXML + private JFXRadioButton fixedTimes; + + MainConfig mainConfig; + VoiceConfig voiceConfig; + + Pane rootPane; + + NameData nameData; + + Logger log = LogManager.getLogger("SettingsPaneControllerLogger"); + + public SettingsPaneController(){ + FXMLLoader loader=new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/SettingsPane.fxml")); + loader.setRoot(this); + loader.setController(this); + try { + loader.load(); + }catch(Exception e){ + log.warn("Error to load settings pane FXML: "+e.toString()); + } + } + + public void setMainConfig(MainConfig mainConfig) { + this.mainConfig = mainConfig; + } + + public void setVoiceConfig(VoiceConfig voiceConfig) { + this.voiceConfig = voiceConfig; + } + + public void setRootPane(Pane rootPane){ + this.rootPane=rootPane; + } + + public void bindProperties(MainConfig mainConfig){ + setMainConfig(mainConfig); + + ignoreOnce.selectedProperty().bindBidirectional(mainConfig.ignorePastPropertyProperty()); + chooseOnce.setSelected(!mainConfig.isIgnorePastProperty()); + + randomTimes.selectedProperty().bindBidirectional(mainConfig.randomTimesPropertyProperty()); + fixedTimes.setSelected(!mainConfig.isRandomTimesProperty()); + + equalModeBtn.selectedProperty().bindBidirectional(mainConfig.equalModePropertyProperty()); + + newAlgoBtn.selectedProperty().bindBidirectional(mainConfig.newAlgoPropertyProperty()); + + voicePlayBtn.selectedProperty().bindBidirectional(mainConfig.voicePlayPropertyProperty()); + + cycleTimesBar.valueProperty().bindBidirectional(mainConfig.cycleTimesPropertyProperty()); + + speedBar.valueProperty().bindBidirectional(mainConfig.speedPropertyProperty()); + + showSayingBtn.selectedProperty().bindBidirectional(mainConfig.showSayingProperty()); + + mainConfig.ignorePastPropertyProperty().addListener((observable, oldValue, isIgnorePast) -> { + if(!isIgnorePast) + { + //如果 忽略被点过的名字 被取消后就把机会均等模式的按钮给取消掉 + equalModeBtn.setSelected(false); + } + }); + } + + public void setToggleGroup(){ + ToggleGroup pastGroup=new ToggleGroup(); + chooseOnce.setToggleGroup(pastGroup); + ignoreOnce.setToggleGroup(pastGroup); + + ToggleGroup fixedTimesGroup=new ToggleGroup(); + randomTimes.setToggleGroup(fixedTimesGroup); + fixedTimes.setToggleGroup(fixedTimesGroup); + } + + @FXML + void showVoiceSettingsPane(ActionEvent event) { + VoiceSettingsPaneController voiceSettingsPaneController=new VoiceSettingsPaneController(); + voiceSettingsPaneController.bindPropertied(voiceConfig); + new DialogMaker(rootPane).createDialogWithOneBtn("语音设置",voiceSettingsPaneController); + } + + @FXML + void showEqualMode(ActionEvent event) { + new DialogMaker(rootPane).createMessageDialog("什么?", + "//有待补充。;-)"); + + } + + @FXML + void clearIgnoreList(ActionEvent event) { + new DialogMaker(rootPane).createDialogWithOKAndCancel("真的吗?","真的要重置吗?",(e)->{ + nameData.clearNumberIgnoreList(); + nameData.clearNameIgnoreList(); + }); + } + + @FXML + void equalBtnAction(ActionEvent event) { + if(!mainConfig.isIgnorePastProperty()){ + equalModeBtn.setSelected(false); + new DialogMaker(rootPane).createMessageDialog("且慢","无法在“概率均分”的模式下使用,如需使用请在“人人有份”模式下启用。"); + } + } + + public void setNameData(NameData nameData) { + this.nameData = nameData; + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/VoiceSettingsPaneController.java b/src/main/java/me/lensferno/dogename/controllers/VoiceSettingsPaneController.java new file mode 100644 index 0000000..4ac0631 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/VoiceSettingsPaneController.java @@ -0,0 +1,85 @@ +package me.lensferno.dogename.controllers; + +import com.jfoenix.controls.JFXComboBox; +import com.jfoenix.controls.JFXSlider; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.layout.VBox; +import me.lensferno.dogename.configs.VoiceConfig; + +import java.util.logging.Logger; + +public class VoiceSettingsPaneController extends VBox { + Logger log = Logger.getLogger("VoiceSettingsPaneControllerLogger"); + + VoiceConfig voiceConfig=new VoiceConfig(); + + + @FXML + private JFXSlider intonationBar; + + @FXML + private JFXComboBox speakerSelectBar; + + @FXML + private JFXSlider voiceSpeedBar; + + public static final ObservableList shownSpeakerList = FXCollections.observableArrayList(); + + private final String[] speakers={ + "1","0","3","4", + "106","110","111","103","5"}; + //度小宇=1,度小美=0,度逍遥=3,度丫丫=4 + //度博文=106,度小童=110,度小萌=111,度米朵=103,度小娇=5 + + public VoiceSettingsPaneController() { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/me/lensferno/dogename/FXMLs/VoiceSettingsPane.fxml")); + loader.setRoot(this); + loader.setController(this); + try { + loader.load(); + } catch (Exception e) { + log.warning("Error to load settings pane FXML: " + e.toString()); + } + if(shownSpeakerList.isEmpty()) { + shownSpeakerList.addAll( + "度小宇=1", "度小美=0", "度逍遥=3", "度丫丫=4", + "度博文=106", "度小童=110", "度小萌=111", "度米朵=103", "度小娇=5"); + } + + speakerSelectBar.setItems(shownSpeakerList); + } + + public void bindPropertied(VoiceConfig voiceConfig){ + + this.voiceConfig=voiceConfig; + + //speakerSelectBar. + + speakerSelectBar.selectionModelProperty().addListener((observable, oldValue, newValue) -> { + System.out.println("what?"+newValue.getSelectedIndex()); + this.voiceConfig.setSpeaker(speakers[newValue.getSelectedIndex()]); + this.voiceConfig.setSelectedSpeaker(newValue.getSelectedIndex()); + }); + + //speakerSelectBar.setValue(this.voiceConfig.getSpeaker()); + + voiceSpeedBar.valueProperty().bindBidirectional(voiceConfig.speedProperty()); + intonationBar.valueProperty().bindBidirectional(voiceConfig.intonationProperty()); + + speakerSelectBar.getSelectionModel().select(this.voiceConfig.getSelectedSpeaker()); + } + + @FXML + void showAdvancedVoiceSettings(ActionEvent event) { + + } + + + +} + + diff --git a/src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByMouse.java b/src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByMouse.java new file mode 100644 index 0000000..6e839c7 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByMouse.java @@ -0,0 +1,33 @@ +package me.lensferno.dogename.controllers.WindowListeners; + +import javafx.event.EventHandler; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; + +public class MoveWindowByMouse implements EventHandler { + + private Stage primaryStage; + private double oldStageX; + private double oldStageY; + private double oldScreenX; + private double oldScreenY; + + public MoveWindowByMouse(Stage stage) { + this.primaryStage = stage; + } + + @Override + public void handle(MouseEvent e) { + if (e.getEventType() == MouseEvent.MOUSE_PRESSED) { + this.oldStageX = this.primaryStage.getX(); + this.oldStageY = this.primaryStage.getY(); + this.oldScreenX = e.getScreenX(); + this.oldScreenY = e.getScreenY(); + + } else if (e.getEventType() == MouseEvent.MOUSE_DRAGGED) { + this.primaryStage.setX(e.getScreenX() - this.oldScreenX + this.oldStageX); + this.primaryStage.setY(e.getScreenY() - this.oldScreenY + this.oldStageY); + } + + } +} diff --git a/src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByTouch.java b/src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByTouch.java new file mode 100644 index 0000000..130dbb7 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByTouch.java @@ -0,0 +1,34 @@ +package me.lensferno.dogename.controllers.WindowListeners; + +import javafx.event.EventHandler; +import javafx.scene.input.TouchEvent; +import javafx.stage.Stage; + +public class MoveWindowByTouch implements EventHandler { + + private Stage primaryStage; + private double oldStageX; + private double oldStageY; + private double oldScreenX; + private double oldScreenY; + + public MoveWindowByTouch(Stage stage) { + this.primaryStage = stage; + } + + @Override + public void handle(TouchEvent e) { + if (e.getEventType() == TouchEvent.TOUCH_PRESSED) { + this.oldStageX = this.primaryStage.getX(); + this.oldStageY = this.primaryStage.getY(); + this.oldScreenX = e.getTouchPoint().getScreenX(); + this.oldScreenY = e.getTouchPoint().getScreenY(); + + } else if (e.getEventType() == TouchEvent.TOUCH_MOVED) { + this.primaryStage.setX(e.getTouchPoint().getScreenX() - this.oldScreenX + this.oldStageX); + this.primaryStage.setY(e.getTouchPoint().getScreenY() - this.oldScreenY + this.oldStageY); + } + + } +} + diff --git a/src/main/java/me/lensferno/dogename/data/History.java b/src/main/java/me/lensferno/dogename/data/History.java new file mode 100644 index 0000000..f4bbd18 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/data/History.java @@ -0,0 +1,92 @@ +package me.lensferno.dogename.data; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.util.ArrayList; + +public class History { + + Logger log = LogManager.getLogger(); + + + private String HISTORY_FILE; + public static final String separator=File.separator; + + ArrayList history; + + public void loadHistory(){ + + HISTORY_FILE="files"+separator+"history.data"; + + try { + File historyFile = new File(HISTORY_FILE); + if (!historyFile.exists()) { + historyFile.getParentFile().mkdirs(); + historyFile.createNewFile(); + + history = new ArrayList<>(); + writeHistory(); + return; + } + + ObjectInputStream ois = new ObjectInputStream(new FileInputStream(historyFile)); + history = (ArrayList) ois.readObject(); + + } catch (EOFException e){ + history =new ArrayList<>(); + log.warn("History file is empty."); + writeHistory(); + }catch (Exception e) { + history = new ArrayList<>(); + log.error("Failed to load history file:"+e.toString()); + e.printStackTrace(); + } + } + + public ArrayList getHistoryList(){ + return history; + } + + public void addHistory(String name){ + if(history.size()>2000) { + history.clear(); + } + history.add((history.size() + 1) +". "+name); + + writeHistory(); + } + + private void writeHistory(){ + + HISTORY_FILE="files"+separator+"history.data"; + File historyFile=new File(HISTORY_FILE); + + try{ + + if (!historyFile.exists()) { + historyFile.createNewFile(); + } + + ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream(historyFile)); + oos.writeObject(history); + oos.close(); + }catch (Exception e){ + log.error("Error in writing history file:"+e); + } + } + + public int downSearch(){ + return 1; + } + + public int upSearch(){ + return 1; + } + + public void clearHistory(){ + this.history.clear(); + } + +} diff --git a/src/main/java/me/lensferno/dogename/data/NameData.java b/src/main/java/me/lensferno/dogename/data/NameData.java new file mode 100644 index 0000000..05f7ae0 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/data/NameData.java @@ -0,0 +1,351 @@ +package me.lensferno.dogename.data; + +import com.google.gson.Gson; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.util.*; + +public class NameData { + + Logger log = LogManager.getLogger("NameDataLogger"); + + private List nameList; + + private List chooseList; + private int listSize = 0; + + + HashSet ignoreNameList=new HashSet<>(); + + HashSet ignoreNumberList=new HashSet<>(); + + File dataFile ;//=new File("namelist.data"); + + boolean newAlgo=true; + SecureRandom secRandom =new SecureRandom(); + + //不做注释了,自己慢慢看。:) + + File nameIgnoreFile =new File("files"+File.separator+"IgnoredNameList.data"); + File numbIgnoreFile =new File("files"+File.separator+"IgnoredNumberList.data"); + + public void writeIgnoreList(String switchy){ + + if(!switchy.equals("not name")) { + try { + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(nameIgnoreFile)); + oos.writeObject(ignoreNameList); + oos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + if(!switchy.equals("not number")) { + try { + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(numbIgnoreFile)); + oos.writeObject(ignoreNumberList); + oos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + + + public void readIgnoreList(){ + + try{ + + if(!nameIgnoreFile.exists()){ + nameIgnoreFile.getParentFile().mkdirs(); + nameIgnoreFile.createNewFile(); + ignoreNameList= new HashSet<>(); + writeIgnoreList("not number"); + return; + } + + ObjectInputStream ois =new ObjectInputStream(new FileInputStream(nameIgnoreFile)); + this.ignoreNameList=(HashSet)ois.readObject(); + + }catch (EOFException e){ + ignoreNameList=new HashSet<>(); + log.warn("Past name list is empty."); + writeIgnoreList("not number"); + }catch (Exception e){ + ignoreNameList=new HashSet<>(); + writeIgnoreList("not number"); + log.warn("Failed to load past name list:"+e.toString()); + e.printStackTrace(); + } + + try{ + + if(!numbIgnoreFile.exists()){ + numbIgnoreFile.getParentFile().mkdirs(); + numbIgnoreFile.createNewFile(); + ignoreNumberList= new HashSet<>(); + writeIgnoreList("not name"); + return; + } + + ObjectInputStream ois =new ObjectInputStream(new FileInputStream(numbIgnoreFile)); + this.ignoreNumberList=(HashSet)ois.readObject(); + + }catch (EOFException e){ + ignoreNumberList=new HashSet<>(); + log.warn("Ignored number list is empty."); + writeIgnoreList("not name"); + }catch (Exception e){ + ignoreNumberList=new HashSet<>(); + log.warn("Failed to load ignored number list"); + writeIgnoreList("not name"); + e.printStackTrace(); + } + + log.info("There are "+ignoreNameList.size()+" names and "+ignoreNumberList.size()+" numbers ignored."); + } + + + public void clearNameIgnoreList(){ + ignoreNameList.clear(); + writeIgnoreList("not number"); + } + + public void clearNumberIgnoreList(){ + ignoreNumberList.clear(); + writeIgnoreList("not name"); + } + + + public HashSet getIgnoreNameList() { + return ignoreNameList; + } + + public void setIgnoreNameList(HashSet ignoreNameList) { + this.ignoreNameList = ignoreNameList; + } + + public HashSet getIgnoreNumberList() { + return ignoreNumberList; + } + + public void setIgnoreNumberList(HashSet ignoreNumberList) { + this.ignoreNumberList = ignoreNumberList; + } + + + public List getNameList() { + return nameList; + } + + public void exportNameList(File path) { + if(path!=null) { + try{ + FileOutputStream oos =new FileOutputStream(path); + oos.write(new Gson().toJson(nameList).getBytes(StandardCharsets.UTF_8)); + oos.close(); + log.info("Exported list to:"+path.getPath()); + }catch (Exception e){log.warn("error in export namelist: "+e.toString());e.printStackTrace();} + + } + } + + public void importNameList(File path) { + if(path!=null) { + + try{ + FileInputStream fis =new FileInputStream(path); + String temp; + BufferedReader bis=new BufferedReader(new InputStreamReader(fis, StandardCharsets.UTF_8)); + StringBuilder sb=new StringBuilder(); + + while ((temp = bis.readLine()) != null) { + sb.append(temp); + sb.append("\n"); + } + + nameList=new Gson().fromJson(sb.toString(),List.class); + log.info("Imported list from:"+path.getPath()); + }catch (Exception e){log.warn("error in import namelist:"+e.toString());e.printStackTrace();} + + } + + } + + public void makeMass() { + + HashSet alreadyList = new HashSet<>(); + List tempList = new LinkedList<>(); + int i; + Random random = new Random(); + while (tempList.size() < nameList.size()) { + i = random.nextInt(nameList.size()); + while (alreadyList.contains(i)) + i = random.nextInt(nameList.size()); + tempList.add(nameList.get(i)); + alreadyList.add(i); + } + nameList.clear(); + nameList.addAll(tempList); + + } + + //------------------------------------------------------ + public void setNewAlgo(boolean newAlgo) { + this.newAlgo=newAlgo; + if(newAlgo) + System.out.println("[INFO]Use SecureRandom"); + else + System.out.println("[INFO]Not use SecureRandom"); + } + //------------------------------------------------------ + + public NameData(){ + + if(System.getProperty("os.name").toLowerCase().contains("window")) + dataFile=new File("files\\Namelist.data"); + else + dataFile=new File("files/Namelist.data"); + + File oldDataFile=new File("D:\\dogename\\files\\data"); + + try{ + + if(oldDataFile.exists()) { + ObjectInputStream ois =new ObjectInputStream(new FileInputStream(oldDataFile)); + this.nameList=(ArrayList)ois.readObject(); + + listSize=nameList.size(); + this.chooseList=new ArrayList<>(nameList); + ois.close(); + oldDataFile.delete(); + saveToFile(); + return; + } + + if(!dataFile.exists()){ + dataFile.getParentFile().mkdirs(); + dataFile.createNewFile(); + nameList= new ArrayList<>(); + saveToFile(); + return; + } + + ObjectInputStream ois =new ObjectInputStream(new FileInputStream(dataFile)); + this.nameList=(ArrayList)ois.readObject(); + + log.info(nameList.size()+" names loaded."); + + listSize=nameList.size(); + this.chooseList=new ArrayList<>(nameList); + + }catch (EOFException EOFe){ + nameList=new ArrayList<>(); + chooseList=new ArrayList<>(); + log.warn("Data file is empty."); + saveToFile(); + }catch (Exception e){ + nameList=new ArrayList<>(); + chooseList=new ArrayList<>(); + saveToFile(); + log.warn("Failed to load data file."); + e.printStackTrace(); + } + + } + + //------------------------------------------------------ + public void add(String text){ + String[] splitedText; + + if(text.contains("\n")&&text.contains("\r")){//-----------windows + splitedText=text.split("\r\n"); + nameList.addAll(Arrays.asList(splitedText)); + }else if(text.contains("\n")){//--------------------------linux,unix + splitedText=text.split("\n"); + nameList.addAll(Arrays.asList(splitedText)); + }else if(text.contains("\r")){//--------------------------macos + splitedText=text.split("\r"); + nameList.addAll(Arrays.asList(splitedText)); + }else { + nameList.add(text); + listSize=nameList.size(); + } + chooseList=new ArrayList<>(nameList); + System.gc(); + } + //------------------------------------------------------ + public String get(int i){ + if(i(nameList); + listSize=nameList.size(); + System.gc(); + + + } + + //------------------------------------------------------ + public boolean isEmpty(){ + return nameList.isEmpty(); + } + + Random random =new Random(); + + //------------------------------------------------------ + public String randomGet(){ + if(newAlgo) + return nameList.get(secRandom.nextInt(nameList.size())); + else + return nameList.get(random.nextInt(nameList.size())); + } + + //------------------------------------------------------ + public String[] getAll(){ + return nameList.toArray(new String[0]); + } + + //------------------------------------------------------ + public void saveToFile(){ + + try{ + ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream(dataFile)); + oos.writeObject(nameList); + oos.close(); + }catch (Exception e){ + e.printStackTrace(); + } + + } + + //------------------------------------------------------ + public void deleteAll(){ + nameList.clear(); + chooseList.clear(); + } + + //------------------------------------------------------ +} diff --git a/src/main/java/me/lensferno/dogename/ocr/Ocr.java b/src/main/java/me/lensferno/dogename/ocr/Ocr.java new file mode 100644 index 0000000..9e28b67 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/ocr/Ocr.java @@ -0,0 +1,101 @@ +package me.lensferno.dogename.ocr; + +import com.baidu.aip.ocr.AipOcr; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.File; +import java.util.HashMap; + +public class Ocr { + + public static final String APP_ID = "17411446"; + public static final String API_KEY = "R2ggZhk6nB7ORE4Ozy9iAPdc"; + public static final String SECRET_KEY = "9f6ECgrltz9v1rww2hQm3EQOl1FFHLGx"; + + AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY); + + public void init(){ + client.setConnectionTimeoutInMillis(2000); + client.setSocketTimeoutInMillis(60000); + } + + String result; + int resultNum=0; + + public boolean identifyPrecisely(String imgFileLoca){ + HashMap params=new HashMap<>(); + params.put("probability","false"); + JSONObject respondJSON=client.accurateGeneral("files"+ File.separator+"ocrCache.png",params); + + if (respondJSON==null){ + result="错误:返回了空的数据。"; + return false; + } + if(!respondJSON.has("words_result")){ + String errorCode=respondJSON.getString("error_code"); + result=findErrorMsg(errorCode); + return false; + } + + resultNum=respondJSON.getInt("words_result_num"); + System.out.println("total result:"+resultNum); + JSONArray resultArray=respondJSON.getJSONArray("words_result"); + + StringBuffer stringBuffer=new StringBuffer(); + + for(int i=0;i{ + + //gushiciJSON=getGushici(); + + String content, title, author, type; + + if((gushiciJSON=getGushici())!=null){ + GushiciData gushiciData=new Gson().fromJson(gushiciJSON,GushiciData.class); + content=gushiciData.getContent(); + title=gushiciData.getTitle(); + author=gushiciData.getAuthor(); + type=gushiciData.getType(); + Platform.runLater(()->{ + topBar.setText(content+" ——"+author+"《"+title+"》"); + GushiciPaneController gushiciPaneController=new GushiciPaneController(content, title, author, type); + new DialogMaker(rootPane).createDialogWithOneBtn("每日古诗词",gushiciPaneController); + }); + } + }).start(); + + } + + static class GushiciData{ + + private String content;//诗歌的内容 + + @SerializedName("origin") + private String title;//诗歌的标题 + + private String author;//诗歌作者 + + @SerializedName("category") + private String type;//诗歌类型 + + public void setContent(String content) { + this.content = content; + } + public String getContent() { + return content; + } + + public void setTitle(String title) { + this.title = title; + } + public String getTitle() { + return title; + } + + public void setAuthor(String author) { + this.author = author; + } + public String getAuthor() { + return author; + } + + public void setType(String type) { + this.type = type; + } + public String getType() { + return type; + } + } +} diff --git a/src/main/java/me/lensferno/dogename/sayings/Hitokoto.java b/src/main/java/me/lensferno/dogename/sayings/Hitokoto.java new file mode 100644 index 0000000..3846a9a --- /dev/null +++ b/src/main/java/me/lensferno/dogename/sayings/Hitokoto.java @@ -0,0 +1,163 @@ +package me.lensferno.dogename.sayings; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import javafx.application.Platform; +import javafx.scene.control.Label; +import javafx.scene.layout.Pane; +import me.lensferno.dogename.utils.DialogMaker; +import me.lensferno.dogename.controllers.HitokotoPaneController; +import me.lensferno.dogename.utils.HtmlRequseter; + +public class Hitokoto { + + + private final String HITOKOTO_API ="https://v1.hitokoto.cn/"; + + String hitokotoJSON = null; + + private String getHitokoto() { + return HtmlRequseter.getHtml(HITOKOTO_API,false); + } + + public void showHitokoto(Pane rootPane, Label topBar){ + + new Thread(()->{ + + //hitokotoJSON = getHitokoto(); + + String hitokoto, from,author,creator, type; + + if((hitokotoJSON = getHitokoto())!=null){ + HitokotoData hitokotoData=new Gson().fromJson(hitokotoJSON, HitokotoData.class); + + hitokoto=hitokotoData.getHitokoto(); + from=hitokotoData.getFrom(); + author=hitokotoData.getAuthor(); + creator=hitokotoData.getCreator(); + type=hitokotoData.getType(); + + Platform.runLater(()->{ + topBar.setText("《"+from+"》:"+hitokoto+" ("+author+")"); + HitokotoPaneController hitokotoPaneController=new HitokotoPaneController(hitokoto, from,author,creator, type); + new DialogMaker(rootPane).createDialogWithOneBtn("每日一句话",hitokotoPaneController); + }); + } + }).start(); + } + + static class HitokotoData { + + private int id; + private String hitokoto; + private String type; + private String from; + + @SerializedName("from_who") + private String author; + + private String creator; + public void setId(int id) { + this.id = id; + } + public int getId() { + return id; + } + + public void setHitokoto(String hitokoto) { + this.hitokoto = hitokoto; + } + public String getHitokoto() { + return hitokoto; + } + + public void setType(String type) { + this.type = type; + } + + /** + * Type: + * a 动画 + * b 漫画 + * c 游戏 + * d 文学 + * e 原创 + * f 来自网络 + * g 其他 + * h 影视 + * i 诗词 + * j 网易云 + * k 哲学 + * l 抖机灵 + * + * @return + */ + + public String getType() { + switch (type){ + case "a" : + type="动画"; + break; + case "b" : + type="漫画"; + break; + case "c" : + type="游戏"; + break; + case "d" : + type="文学"; + break; + case "e" : + type="原创"; + break; + case "f" : + type="来自网络"; + break; + case "g" : + type="其他"; + break; + case "h" : + type="影视"; + break; + case "i" : + type="诗词"; + break; + case "j" : + type="网易云"; + break; + case "k" : + type="哲学"; + break; + case "l" : + type="抖机灵"; + break; + default: + type="未知"; + + } + return type; + } + + public void setFrom(String from) { + this.from = from; + } + public String getFrom() { + return from; + } + + public void setAuthor(String author) { + this.author = author; + } + public String getAuthor() { + return author; + } + + public void setCreator(String creator) { + this.creator = creator; + } + public String getCreator() { + return creator; + } + + } +} diff --git a/src/main/java/me/lensferno/dogename/utils/Clipboard.java b/src/main/java/me/lensferno/dogename/utils/Clipboard.java new file mode 100644 index 0000000..7081e24 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/utils/Clipboard.java @@ -0,0 +1,32 @@ +package me.lensferno.dogename.utils; + +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; + +public class Clipboard { + + public static void copyToClipboard(String text) { + java.awt.datatransfer.Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + Transferable trans = new StringSelection(text); + clipboard.setContents(trans, null); + } + + public static String getClipboardString() { + java.awt.datatransfer.Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + Transferable trans = clipboard.getContents(null); + + if (trans != null) { + if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) { + try { + return (String) trans.getTransferData(DataFlavor.stringFlavor); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + return null; + } +} diff --git a/src/main/java/me/lensferno/dogename/utils/DialogMaker.java b/src/main/java/me/lensferno/dogename/utils/DialogMaker.java new file mode 100644 index 0000000..b8587f3 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/utils/DialogMaker.java @@ -0,0 +1,113 @@ +package me.lensferno.dogename.utils; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXDialog; +import com.jfoenix.controls.JFXDialogLayout; +import javafx.beans.NamedArg; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Paint; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import javafx.scene.text.Text; + + +public class DialogMaker { + Pane rootPane; + + public DialogMaker(@NamedArg("rootPane") Pane rootPane){ + this.rootPane=rootPane; + } + + + JFXDialog dialog; + + public void createMessageDialog(@NamedArg("title") String title, @NamedArg("message") String message){ + JFXButton OKButton = new JFXButton("了解!"); + OKButton.setFont(Font.font("Microsoft YaHei",FontWeight.BOLD,12)); + OKButton.setPrefWidth(60); + OKButton.setPrefHeight(30); + + Text messageText=new Text(message); + messageText.setFont(Font.font("Microsoft YaHei",14)); + + createDialog(title,messageText,OKButton); + } + + //创建只有一个按钮的dialog + public void createDialogWithOneBtn(@NamedArg("title") String title, @NamedArg("theBody") Node body){ + //dialog.setPrefHeight(rootPane.getPrefHeight()); + //dialog.setPrefWidth(rootPane.getPrefWidth()); + + JFXButton OKButton = new JFXButton("好的!"); + OKButton.setFont(Font.font("Microsoft YaHei",FontWeight.BOLD,12)); + OKButton.setPrefWidth(60); + OKButton.setPrefHeight(30); + + createDialog(title,body,OKButton); + + dialog.show(); + } + + //创建有OK和cancel按钮的dialog + public void createDialogWithOKAndCancel(@NamedArg("title") String title, @NamedArg("message") String message, @NamedArg("OKEvent") EventHandler OKEvent){ + //dialog.setPrefHeight(rootPane.getPrefHeight()); + //dialog.setPrefWidth(rootPane.getPrefWidth()); + + JFXButton CancelButton = new JFXButton("手滑了"); + CancelButton.setFont(Font.font("Microsoft YaHei",FontWeight.BOLD,12)); + CancelButton.setPrefWidth(60); + CancelButton.setPrefHeight(30); + + JFXButton OKButton = new JFXButton("是!"); + OKButton.setFont(Font.font("Microsoft YaHei",FontWeight.BOLD,12)); + OKButton.setPrefWidth(60); + OKButton.setPrefHeight(30); + OKButton.setTextFill(Paint.valueOf("red")); + OKButton.addEventHandler(ActionEvent.ACTION,e -> {dialog.close();}); + OKButton.addEventHandler(ActionEvent.ACTION,OKEvent); + + Text messageText=new Text(message); + messageText.setFont(Font.font("Microsoft YaHei",14)); + + createDialog(title,messageText,CancelButton,OKButton); + + dialog.show(); + } + + public void createDialog(@NamedArg("title") String title, @NamedArg("theBody") Node body, @NamedArg("buttons") JFXButton...buttons){ + + JFXDialogLayout content = new JFXDialogLayout(); + + Label titleLabel=new Label(title); + titleLabel.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD,20)); + content.setHeading(titleLabel); + + content.setBody(body); + content.setAlignment(Pos.CENTER); + + StackPane tempPane=new StackPane(); + tempPane.setPrefHeight(rootPane.getPrefHeight()); + tempPane.setPrefWidth(rootPane.getPrefWidth()); + rootPane.getChildren().add(tempPane); + + dialog = new JFXDialog(tempPane,content,JFXDialog.DialogTransition.TOP); + + dialog.setOnDialogClosed(event -> rootPane.getChildren().remove(tempPane)); + + for (JFXButton button : buttons) { + button.addEventHandler(ActionEvent.ACTION, e -> { + dialog.close(); + }); + } + + content.setActions(buttons); + + dialog.show(); + } +} diff --git a/src/main/java/me/lensferno/dogename/utils/FileProcessor.java b/src/main/java/me/lensferno/dogename/utils/FileProcessor.java new file mode 100644 index 0000000..94152ab --- /dev/null +++ b/src/main/java/me/lensferno/dogename/utils/FileProcessor.java @@ -0,0 +1,25 @@ +package me.lensferno.dogename.utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; + +public class FileProcessor { + + static Logger log = LogManager.getLogger(); + + public static void writeFile(byte[] bytes, File file){ + try { + FileOutputStream fileOutputStream=new FileOutputStream(file); + fileOutputStream.write(bytes); + fileOutputStream.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + }catch (Exception e){ + log.error("Error in writting file"+"\""+file.getName()+"\""+":"+e); + } + } +} diff --git a/src/main/java/me/lensferno/dogename/utils/HtmlRequseter.java b/src/main/java/me/lensferno/dogename/utils/HtmlRequseter.java new file mode 100644 index 0000000..eb52641 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/utils/HtmlRequseter.java @@ -0,0 +1,70 @@ +package me.lensferno.dogename.utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.zip.GZIPInputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +public class HtmlRequseter { + + static Logger log = LogManager.getLogger(); + + public static String getHtml(String address,boolean output) + { + StringBuilder sb = new StringBuilder(); + try { + BufferedReader bis; + URL url = new URL(address); + URLConnection conn = url.openConnection(); + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36"); + + conn.setRequestProperty("Accept-Encoding", "gzip,deflate"); + conn.connect(); + + System.out.println("--------------------------------------------------------------------"); + System.out.println("[INFO]Getting:"+conn.getURL()); + System.out.println("[INFO]Content compress type:"+conn.getContentEncoding()); + + InputStream is = conn.getInputStream(); + String connEncoding=conn.getContentEncoding(); + + if(connEncoding==null) + connEncoding="none"; + + switch (connEncoding) { + case "deflate": + InflaterInputStream deflate = new InflaterInputStream(is, new Inflater(true)); + bis = new BufferedReader(new InputStreamReader(deflate, StandardCharsets.UTF_8)); + break; + case "gzip": + GZIPInputStream gzip = new GZIPInputStream(is); + bis = new BufferedReader(new InputStreamReader(gzip, StandardCharsets.UTF_8)); + break; + default: + bis = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + break; + } + String temp; + while ((temp = bis.readLine()) != null) { + sb.append(temp); + sb.append("\n"); + } + }catch(Exception e){ + log.error("Error in getting HTML:"+e); + return null; + } + + if(output) + System.out.println("[INFO]Got:"+sb.toString()); + + return sb.toString(); + } +} diff --git a/src/main/java/me/lensferno/dogename/voice/Token.java b/src/main/java/me/lensferno/dogename/voice/Token.java new file mode 100644 index 0000000..443e4a1 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/voice/Token.java @@ -0,0 +1,53 @@ +package me.lensferno.dogename.voice; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +public class Token implements Serializable { + + /* +返回 +需要根据 Content-Type的头部来确定是否服务端合成成功。 + +如果合成成功,返回的Content-Type以“audio”开头 + +aue =3 ,返回为二进制mp3文件,具体header信息 Content-Type: audio/mp3; +aue =4 ,返回为二进制pcm文件,具体header信息 Content-Type:audio/basic;codec=pcm;rate=16000;channel=1 +aue =5 ,返回为二进制pcm文件,具体header信息 Content-Type:audio/basic;codec=pcm;rate=8000;channel=1 +aue =6 ,返回为二进制wav文件,具体header信息 Content-Type: audio/wav; +如果合成出现错误,则会返回json文本,具体header信息为:Content-Type: application/json。其中sn字段主要用于DEBUG追查问题,如果出现问题,可以提供sn帮助确认问题。 + */ + + private long expTime; + + @SerializedName("access_token") + private String accessToken; + @SerializedName("expires_in") + private long expiresIn; + + public void setExpTime() { + this.expTime = System.currentTimeMillis() + (expiresIn - 3600) * 1000; + } + + public boolean isTokenTimeOut() { + return System.currentTimeMillis() > expTime; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getAccessToken() { + return accessToken; + } + + public void setExpiresIn(long expiresIn) { + this.expiresIn = expiresIn; + } + + public long getExpiresIn() { + return expiresIn; + } + +} diff --git a/src/main/java/me/lensferno/dogename/voice/TokenManager.java b/src/main/java/me/lensferno/dogename/voice/TokenManager.java new file mode 100644 index 0000000..56ae2cf --- /dev/null +++ b/src/main/java/me/lensferno/dogename/voice/TokenManager.java @@ -0,0 +1,174 @@ +package me.lensferno.dogename.voice; + +import com.google.gson.Gson; +import me.lensferno.dogename.utils.HtmlRequseter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; + +public class TokenManager { + + Logger log= LogManager.getLogger(); + + public static final String separator=File.separator; + + String cachedVoicePath="caches\\voice\\"; + + final private int TOKEN_NULL = -2; + final private int TOKEN_EXPIRED = -1; + final private int TOKEN_OK = 0; + + final String API_KEY="dIHCtamVdD0ERO1yyFir2iI4"; + final String SEC_KEY="HmpBQY3gG4PyZ0cmudnCbMeoMcMejuuW"; + + final String TOKEN_API_URL ="https://openapi.baidu.com/oauth/2.0/token"; + + File tokenFile=new File("API_voice.token"); + + private Token token=null; + + String tokenStatus="ok"; + + private void updateTokenStatus(int statusCode){ + switch(statusCode){ + case TOKEN_OK: + tokenStatus="ok"; + break; + + case TOKEN_EXPIRED: + if(netAvailable()){ refreshToken();} + + if(checkTokenAvailable()!=0){ tokenStatus="not ok";} + break; + + case TOKEN_NULL: + if(netAvailable()){ refreshToken();} + + if(checkTokenAvailable()!=0){ tokenStatus="not ok";} + break; + + default : + tokenStatus="not ok"; + break; + } + } + + private void refreshToken(){ + + fetchToken(); + writeToken(); + } + + + public void init(){ + + if(tokenFile.exists()){ + loadToken(); + updateTokenStatus(checkTokenAvailable()); + + }else{ + + if(netAvailable()){ + + refreshToken(); + + updateTokenStatus(checkTokenAvailable()); + + }else { + tokenStatus="not ok"; + } + + } + } + + public String getTokenStatus() { + return tokenStatus; + } + + public Token getToken() { + return token; + } + + private int checkTokenAvailable() { + + //token是空的就返回-2 + if (token == null || token.getAccessToken() == null) { + log.info("Token was null"); + return -2; + } + + //token过期了就返回-1 + if (token.isTokenTimeOut()) { + log.info("Token expired."); + return -1; + } + + //正常的话就返回0 + log.info("Token OK."); + return 0; + } + + + void fetchToken(){ + try{ + token=new Gson().fromJson( + HtmlRequseter.getHtml( + TOKEN_API_URL + + "?grant_type=client_credentials&client_id=" + API_KEY + + "&client_secret=" + SEC_KEY, + true) + ,Token.class); + + token.setExpTime(); + }catch (Exception e){ + log.error("Error to get Token:"+e); + token=null; + } + } + + private boolean netAvailable(){ + try { + + URL sourcesURL = new URL("http://www.baidu.com"); + HttpURLConnection connection = (HttpURLConnection) sourcesURL.openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36"); + connection.connect(); + + InputStream stream = connection.getInputStream(); + stream.read(); + stream.close(); + + return true; + }catch (Exception e){ + log.info("Network is not available."); + return false; + } + } + + private void loadToken(){ + ObjectInputStream ois; + try{ + ois =new ObjectInputStream(new FileInputStream(tokenFile)); + this.token =(Token) ois.readObject(); + ois.close(); + }catch (Exception e){ + log.error("Error in loading Token:"+e); + this.token=null; + } + } + + private void writeToken(){ + + try{ + ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream(tokenFile)); + oos.writeObject(token); + oos.close(); + }catch (Exception e){ + log.error("Error in writing Token:"+e); + } + } + +} diff --git a/src/main/java/me/lensferno/dogename/voice/VoicePlayer.java b/src/main/java/me/lensferno/dogename/voice/VoicePlayer.java new file mode 100644 index 0000000..6871076 --- /dev/null +++ b/src/main/java/me/lensferno/dogename/voice/VoicePlayer.java @@ -0,0 +1,195 @@ +package me.lensferno.dogename.voice; + +import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader; +import me.lensferno.dogename.utils.FileProcessor; +import okhttp3.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import javax.sound.sampled.*; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.URLEncoder; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +public class VoicePlayer { + + public static final String separator=File.separator; + + Logger log= LogManager.getLogger("VoicePlayerLogger"); + + private final String VOICE_API="https://tsn.baidu.com/text2audio"; + + Token token; + + public VoicePlayer(Token token){ + this.token=token; + + } + + String cachedVoicePath="caches"+separator+"voice"+separator; + + File cacheDir =new File(cachedVoicePath); + + OkHttpClient okHttpClient=new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10,TimeUnit.SECONDS) + .readTimeout(10,TimeUnit.SECONDS) + .build(); + + + public void playVoice(String name,String speaker,String intonation,String speed) { + + String cachedVoiceName; + cachedVoiceName = name + "_" + speaker+ "_" + speed +"_"+intonation; + + File cachedVoice = new File(cachedVoicePath + cachedVoiceName + ".mp3"); + + if (!cachedVoice.exists()) { + System.out.println("Voice of "+cachedVoice+" not exists,fetch from network."); + getVoiceData(name,speaker,speed,intonation,cachedVoice); + //playSound(cachedVoice); + + } else { + new Thread(() -> { + System.out.println("Voice of "+cachedVoice+" exists,playing cache."); + playSound(cachedVoice); + }).start(); + } + + } + + private void getVoiceData(String name,String speaker,String speed,String intonation,File cachedVoice){ + + new Thread(() -> { + try{ + + FormBody formBody=new FormBody.Builder() + .add("tex",URLEncoder.encode(name,"utf-8")) + .add("tok",token.getAccessToken()) + .add("cuid",getMACAddress()) + .add("ctp","1") + .add("lan","zh") + .add("spd",speed) + .add("per",speaker) + .add("pit",intonation) + .add("aue","3") + .build(); + + Request request=new Request.Builder() + .url(VOICE_API) + .header("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36") + .post(formBody) + .build(); + + + okHttpClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + log.warn("Failed to get voice:"+e.toString()); + } + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + if(response.header("Content-type").contains("json")){ + log.warn("Request error:"+response.toString()); + }else { + boolean success=cacheVoiceFile(response,cachedVoice); + if (success) { + log.info("cache voice of "+name+" to file "+cachedVoice.getPath()+" success"); + playSound(cachedVoice); + } + } + } + }); + + }catch(Exception e){ + e.printStackTrace(); + } + + }).start(); + } + + private boolean cacheVoiceFile(Response response,File cacheVoice){ + + try { + + if(!cacheDir.exists()) + cacheDir.mkdirs(); + + if(!cacheVoice.exists()) + cacheVoice.createNewFile(); + + //FileOutputStream cacheFile=new FileOutputStream(cacheVoice); + FileProcessor.writeFile(response.body().bytes(),cacheVoice); + //IOUtils.write(response.body().bytes(),cacheFile); + return true; + } catch (Exception e) { + e.printStackTrace(); + log.warn("Error to cache voice file:"+e.toString()); + return false; + } + + } + + + private void playSound(File file) { + + try { + //使用 mp3spi 解码 mp3 音频文件 + MpegAudioFileReader mp = new MpegAudioFileReader(); + AudioInputStream stream = mp.getAudioInputStream(file); + AudioFormat baseFormat = stream.getFormat(); + //设定输出格式为pcm格式的音频文件 + AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16, baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false); + // 输出到音频 + stream = AudioSystem.getAudioInputStream(format, stream); + AudioFormat target = stream.getFormat(); + DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, target, AudioSystem.NOT_SPECIFIED); + SourceDataLine line; + int len; + line = (SourceDataLine) AudioSystem.getLine(dinfo); + line.open(target); + line.start(); + byte[] buffer = new byte[1024]; + while ((len = stream.read(buffer)) > 0) { + line.write(buffer, 0, len); + } + line.drain(); + line.stop(); + line.close(); + } catch (Exception e) { + log.warn("Error to play voice audio:"+e.toString()); + e.printStackTrace(); + } + } + + + private static String getMACAddress() { + + try{ + + byte[] mac = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress(); + + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < mac.length; i++) { + if (i != 0) { + sb.append("-"); + } + String s = Integer.toHexString(mac[i] & 0xFF); + sb.append(s.length() == 1 ? 0 + s : s); + } + return sb.toString().toUpperCase(); + + }catch (Exception e){ + return String.valueOf(new Random().nextLong()); + } + + } + +} diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..ccf713c --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: me.lensferno.dogename.Main + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/AdvancedVoiceSettingsPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/AdvancedVoiceSettingsPane.fxml new file mode 100644 index 0000000..a4be1ce --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/AdvancedVoiceSettingsPane.fxml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/GushiciPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/GushiciPane.fxml new file mode 100644 index 0000000..9d1bdeb --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/GushiciPane.fxml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/HistoryPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/HistoryPane.fxml new file mode 100644 index 0000000..6d8ebdf --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/HistoryPane.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/HitokotoPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/HitokotoPane.fxml new file mode 100644 index 0000000..b0dc929 --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/HitokotoPane.fxml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/MainInterface.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/MainInterface.fxml new file mode 100644 index 0000000..60f439c --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/MainInterface.fxml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/MiniPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/MiniPane.fxml new file mode 100644 index 0000000..e281f91 --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/MiniPane.fxml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/NameListPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/NameListPane.fxml new file mode 100644 index 0000000..d91cfb2 --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/NameListPane.fxml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/NameManagerPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/NameManagerPane.fxml new file mode 100644 index 0000000..4611d9b --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/NameManagerPane.fxml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/NumberSettingPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/NumberSettingPane.fxml new file mode 100644 index 0000000..7b57910 --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/NumberSettingPane.fxml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/OcrPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/OcrPane.fxml new file mode 100644 index 0000000..394fdc9 --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/OcrPane.fxml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/ProgramInfoPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/ProgramInfoPane.fxml new file mode 100644 index 0000000..6da20e8 --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/ProgramInfoPane.fxml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/SettingsPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/SettingsPane.fxml new file mode 100644 index 0000000..6d6954f --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/SettingsPane.fxml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/me/lensferno/dogename/FXMLs/VoiceSettingsPane.fxml b/src/main/resources/me/lensferno/dogename/FXMLs/VoiceSettingsPane.fxml new file mode 100644 index 0000000..2f80b09 --- /dev/null +++ b/src/main/resources/me/lensferno/dogename/FXMLs/VoiceSettingsPane.fxml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +