重置项目结构

main
lensfrex 4 years ago
commit aa6dee90be
No known key found for this signature in database
GPG Key ID: E10FF75B77E1924D
  1. 9
      .gitignore
  2. 165
      LICENSE
  3. 68
      README.md
  4. 33
      dogename.iml
  5. 109
      pom.xml
  6. BIN
      res/icon.ico
  7. BIN
      res/top.png
  8. 229
      res/usage.md
  9. 41
      res/you-want.md
  10. 34
      src/main/java/log4j2.xml
  11. 21
      src/main/java/me/lensferno/dogename/DataReleaser.java
  12. 66
      src/main/java/me/lensferno/dogename/Main.java
  13. 356
      src/main/java/me/lensferno/dogename/choose/Chooser.java
  14. 212
      src/main/java/me/lensferno/dogename/configs/ConfigLoader.java
  15. 4
      src/main/java/me/lensferno/dogename/configs/ConfigValuesBean.java
  16. 242
      src/main/java/me/lensferno/dogename/configs/MainConfig.java
  17. 75
      src/main/java/me/lensferno/dogename/configs/VoiceConfig.java
  18. 27
      src/main/java/me/lensferno/dogename/configs/adapters/BooleanPropertyAdapter.java
  19. 27
      src/main/java/me/lensferno/dogename/configs/adapters/DoublePropertyAdapter.java
  20. 26
      src/main/java/me/lensferno/dogename/configs/adapters/IntegerPropertyAdapter.java
  21. 26
      src/main/java/me/lensferno/dogename/configs/adapters/StringPropertyAdapter.java
  22. 39
      src/main/java/me/lensferno/dogename/controllers/GushiciPaneController.java
  23. 126
      src/main/java/me/lensferno/dogename/controllers/HistoryPaneController.java
  24. 38
      src/main/java/me/lensferno/dogename/controllers/HitokotoPaneController.java
  25. 337
      src/main/java/me/lensferno/dogename/controllers/MainInterfaceController.java
  26. 191
      src/main/java/me/lensferno/dogename/controllers/MiniPaneController.java
  27. 191
      src/main/java/me/lensferno/dogename/controllers/NameManagerPaneController.java
  28. 39
      src/main/java/me/lensferno/dogename/controllers/NumberSettingsPaneController.java
  29. 93
      src/main/java/me/lensferno/dogename/controllers/OcrPaneController.java
  30. 137
      src/main/java/me/lensferno/dogename/controllers/ProgramInfoPaneController.java
  31. 157
      src/main/java/me/lensferno/dogename/controllers/SettingsPaneController.java
  32. 85
      src/main/java/me/lensferno/dogename/controllers/VoiceSettingsPaneController.java
  33. 33
      src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByMouse.java
  34. 34
      src/main/java/me/lensferno/dogename/controllers/WindowListeners/MoveWindowByTouch.java
  35. 92
      src/main/java/me/lensferno/dogename/data/History.java
  36. 351
      src/main/java/me/lensferno/dogename/data/NameData.java
  37. 101
      src/main/java/me/lensferno/dogename/ocr/Ocr.java
  38. 205
      src/main/java/me/lensferno/dogename/ocr/ScreenCapture.java
  39. 27
      src/main/java/me/lensferno/dogename/resources/LibLicense.txt
  40. 6
      src/main/java/me/lensferno/dogename/resources/LicenseText.java
  41. 5
      src/main/java/me/lensferno/dogename/resources/MainInterfaceImage.java
  42. 5
      src/main/java/me/lensferno/dogename/resources/dogename.java
  43. 86
      src/main/java/me/lensferno/dogename/sayings/Gushici.java
  44. 163
      src/main/java/me/lensferno/dogename/sayings/Hitokoto.java
  45. 32
      src/main/java/me/lensferno/dogename/utils/Clipboard.java
  46. 113
      src/main/java/me/lensferno/dogename/utils/DialogMaker.java
  47. 25
      src/main/java/me/lensferno/dogename/utils/FileProcessor.java
  48. 70
      src/main/java/me/lensferno/dogename/utils/HtmlRequseter.java
  49. 53
      src/main/java/me/lensferno/dogename/voice/Token.java
  50. 174
      src/main/java/me/lensferno/dogename/voice/TokenManager.java
  51. 195
      src/main/java/me/lensferno/dogename/voice/VoicePlayer.java
  52. 3
      src/main/resources/META-INF/MANIFEST.MF
  53. 53
      src/main/resources/me/lensferno/dogename/FXMLs/AdvancedVoiceSettingsPane.fxml
  54. 25
      src/main/resources/me/lensferno/dogename/FXMLs/GushiciPane.fxml
  55. 48
      src/main/resources/me/lensferno/dogename/FXMLs/HistoryPane.fxml
  56. 25
      src/main/resources/me/lensferno/dogename/FXMLs/HitokotoPane.fxml
  57. 107
      src/main/resources/me/lensferno/dogename/FXMLs/MainInterface.fxml
  58. 30
      src/main/resources/me/lensferno/dogename/FXMLs/MiniPane.fxml
  59. 9
      src/main/resources/me/lensferno/dogename/FXMLs/NameListPane.fxml
  60. 80
      src/main/resources/me/lensferno/dogename/FXMLs/NameManagerPane.fxml
  61. 36
      src/main/resources/me/lensferno/dogename/FXMLs/NumberSettingPane.fxml
  62. 84
      src/main/resources/me/lensferno/dogename/FXMLs/OcrPane.fxml
  63. 58
      src/main/resources/me/lensferno/dogename/FXMLs/ProgramInfoPane.fxml
  64. 140
      src/main/resources/me/lensferno/dogename/FXMLs/SettingsPane.fxml
  65. 61
      src/main/resources/me/lensferno/dogename/FXMLs/VoiceSettingsPane.fxml

9
.gitignore vendored

@ -0,0 +1,9 @@
/out
/files
/caches
/target
*.token
/target/
/log/
/logs/
.idea

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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.

@ -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)

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.6" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.14" level="project" />
<orderEntry type="library" name="Maven: com.jfoenix:jfoenix:8.0.9" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-core:2.13.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.13.2" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.6" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okhttp3:okhttp:4.2.2" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okio:okio:2.2.2" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.3.50" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains:annotations:13.0" level="project" />
<orderEntry type="library" name="Maven: com.googlecode.soundlibs:mp3spi:1.9.5.4" level="project" />
<orderEntry type="library" name="Maven: com.googlecode.soundlibs:jlayer:1.0.1.4" level="project" />
<orderEntry type="library" name="Maven: junit:junit:3.8.2" level="project" />
<orderEntry type="library" name="Maven: com.googlecode.soundlibs:tritonus-share:0.3.7.4" level="project" />
<orderEntry type="library" name="Maven: com.baidu.aip:java-sdk:4.12.0" level="project" />
<orderEntry type="library" name="Maven: org.json:json:20160810" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.7.25" level="project" />
</component>
</module>

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.lensferno.dogename</groupId>
<artifactId>dogename</artifactId>
<version>3.3</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<mainClass>me.lensferno.dogename.Main</mainClass>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.14</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.jfoenix/jfoenix -->
<dependency>
<groupId>com.jfoenix</groupId>
<artifactId>jfoenix</artifactId>
<version>8.0.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.googlecode.soundlibs/mp3spi -->
<dependency>
<groupId>com.googlecode.soundlibs</groupId>
<artifactId>mp3spi</artifactId>
<version>1.9.5.4</version>
</dependency>
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.12.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>central</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<layout>default</layout>
<!-- 是否开启发布版构件下载 -->
<releases>
<enabled>true</enabled>
</releases>
<!-- 是否开启快照版构件下载 -->
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

@ -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. 小窗模式
- 点击主界面的“小窗模式”按钮,可以将窗口变成小版界面,仅保留“安排一下”和“恢复”按钮,以及一个用于显示名字的文本。这个时候窗口总在最前端,拖动非按钮区域可以移动窗口。点击“恢复”按钮即可恢复原来的窗口状态。

@ -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 "下载")下来看看吧😀

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="error">
<!--先定义所有的appender-->
<appenders>
<!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
<!--这个都知道是输出日志的格式-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %l:%m%n "/>
</Console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
<File name="log" fileName="log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %l:%m%n "/>
</File>
<!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFile" fileName="log/app.log"
filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern=" %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="50MB"/>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!--建立一个默认的root的logger-->
<root level="trace">
<appender-ref ref="RollingFile"/>
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>

@ -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));
}
}

@ -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());
}
}
}
}

@ -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;
}
}

@ -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);
}
}
}

@ -0,0 +1,4 @@
package me.lensferno.dogename.configs;
public class ConfigValuesBean {
}

@ -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;
}
}

@ -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) {
}
}

@ -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<SimpleBooleanProperty>, JsonDeserializer<SimpleBooleanProperty> {
@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());
}
}
}

@ -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<SimpleDoubleProperty>, JsonDeserializer<SimpleDoubleProperty> {
@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());
}
}
}

@ -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<SimpleIntegerProperty>, JsonDeserializer<SimpleIntegerProperty> {
@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());
}
}
}

@ -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<SimpleStringProperty>, JsonDeserializer<SimpleStringProperty> {
@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());
}
}
}

@ -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);
}
}

@ -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<String> 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<String> 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<historyArrayList.length-1){
pointer=0;
return;
}
}
pointOutSearchResult(pointer);
pointer++;
if (pointer<historyArrayList.length-1){
pointer=0;
}
}
@FXML
void clearHistory(){
new DialogMaker(rootPane).createDialogWithOKAndCancel("且慢!","真的要清除全部历史记录吗?",(e)-> {
this.history.clearHistory();
pointer=0;
});
}
}

@ -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);
}
}

@ -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<String> ignoreNameList;
HashSet<String> 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;
}
}

@ -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<MouseEvent> mouseHandler=new MoveWindowByMouse(currentStage);
chosenNameLabel.setOnMousePressed(mouseHandler);
chosenNameLabel.setOnMouseDragged(mouseHandler);
EventHandler<TouchEvent> 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()
);
}
}

@ -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<String> 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<String> 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());
}
}

@ -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() );
}
}

@ -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());
}
}

@ -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();
}
}
}

@ -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;
}
}

@ -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<String> speakerSelectBar;
@FXML
private JFXSlider voiceSpeedBar;
public static final ObservableList<String> 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) {
}
}

@ -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<MouseEvent> {
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);
}
}
}

@ -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<TouchEvent> {
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);
}
}
}

@ -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<String> 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<String>) 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<String> 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();
}
}

@ -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<String> nameList;
private List<String> chooseList;
private int listSize = 0;
HashSet<String> ignoreNameList=new HashSet<>();
HashSet<String> 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<String> getIgnoreNameList() {
return ignoreNameList;
}
public void setIgnoreNameList(HashSet<String> ignoreNameList) {
this.ignoreNameList = ignoreNameList;
}
public HashSet<String> getIgnoreNumberList() {
return ignoreNumberList;
}
public void setIgnoreNumberList(HashSet<String> ignoreNumberList) {
this.ignoreNumberList = ignoreNumberList;
}
public List<String> 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<Integer> alreadyList = new HashSet<>();
List<String> 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<listSize-1)
return null;
else
return nameList.get(i);
}
//------------------------------------------------------
public int getSize(){
return nameList.size();
}
//------------------------------------------------------
public void delete(String name){
if(nameList.isEmpty())
return;
nameList.remove(name);
ignoreNameList.remove(name);
chooseList=new ArrayList<>(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();
}
//------------------------------------------------------
}

@ -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<String,String> 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<resultArray.length();i++){
stringBuffer.append(resultArray.getJSONObject(i).getString("words")).append("\n");
}
result=stringBuffer.toString();
return true;
}
public String getResult() {
return result;
}
public int getResultNum() {
return resultNum;
}
private String findErrorMsg(String errorCode){
switch (errorCode){
case "1":
return "服务器内部错误,请尝试再次请求。";
case "3":
return "调用的API不存在。";
case "4":
return "集群超限额,请尝试再次请求。";
case "17":
return "每天请求量超限额。";
case "SDK100":
return "错误:图像文件过大。";
case "SDK101":
return "错误:图片边长不符合要求。";
case "SDK102":
return "错误:读取图片文件错误。";
case "SDK106":
return "错误:UID格式错误。";
case "SDK107":
return "错误:UID大小错误。";
case "SDK108":
return "错误:连接超时或读取数据超时,请检查网络连接。";
case "SDK109":
return "错误:图片格式不支持。";
case "SDK110":
return "错误:无效的请求ID。";
case "SDK111":
return "错误:等待异步请求结果超时。";
case "SDK112":
return "错误:数据下载失败。";
case "282000":
return "服务器内部错误,如果您使用的是\n高精度接口,原因可能是您上传的图片\n中文字过多,识别超时导致的\n建议您对图片进行切割后再识别,\n其他情况请再次请求。";
default:
return "未知错误。错误码:"+errorCode;
}
}
}

@ -0,0 +1,205 @@
package me.lensferno.dogename.ocr;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
//edited code from https://blog.csdn.net/caoyuan10036/article/details/7199505
public class ScreenCapture {
// test main
/*
public static void main(String[] args) {
File tempFile = new File( "files"+File.separator+"ocr.png");
ScreenCapture capture = ScreenCapture.getInstance();
capture.captureImage();
JLabel imagebox = new JLabel();
imagebox.setIcon(capture.getPickedIcon());
try {
capture.saveToFile(tempFile);
System.out.println("Over");
} catch (IOException e) {
e.printStackTrace();
}
}
*/
public static final String SCREEN_CAPTURE_LOCA="files"+File.separator+"ocrCache.png";
private static boolean canceled =false;
public static boolean getScreenCapture(){
try {
canceled=false;
File tempFile = new File(SCREEN_CAPTURE_LOCA);
ScreenCapture capture = ScreenCapture.getInstance();
capture.captureImage();
if(canceled){
return false;
}
JLabel imagebox = new JLabel();
imagebox.setIcon(capture.getPickedIcon());
capture.saveToFile(tempFile);
System.out.println("Over");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private ScreenCapture() {
try {
robot = new Robot();
} catch (AWTException e) {
System.err.println("Internal Error: " + e);
e.printStackTrace();
}
JPanel cp = (JPanel) dialog.getContentPane();
cp.setLayout(new BorderLayout());
labFullScreenImage.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evn) {
if (evn.getButton()==MouseEvent.BUTTON3){
canceled=true;
System.out.println("captureCancel");
dialog.setVisible(false);
return;
}
isFirstPoint = true;
pickedImage = fullScreenImage.getSubimage(recX, recY, recW,
recH);
dialog.setVisible(false);
}
});
labFullScreenImage.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent evn) {
if (isFirstPoint) {
x1 = evn.getX();
y1 = evn.getY();
isFirstPoint = false;
} else {
x2 = evn.getX();
y2 = evn.getY();
int maxX = Math.max(x1, x2);
int maxY = Math.max(y1, y2);
int minX = Math.min(x1, x2);
int minY = Math.min(y1, y2);
recX = minX;
recY = minY;
recW = maxX - minX;
recH = maxY - minY;
labFullScreenImage.drawRectangle(recX, recY, recW, recH);
}
}
public void mouseMoved(MouseEvent e) {
labFullScreenImage.drawCross(e.getX(), e.getY());
//messageLabel.setLocation(e.getX(), e.getY());
}
});
cp.add(BorderLayout.CENTER, labFullScreenImage);
//cp.add(messageLabel);
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
dialog.setAlwaysOnTop(true);
dialog.setMaximumSize(Toolkit.getDefaultToolkit().getScreenSize());
dialog.setUndecorated(true);
dialog.setSize(dialog.getMaximumSize());
dialog.setModal(true);
}
// Singleton Pattern
public static ScreenCapture getInstance() {
return defaultCapturer;
}
/** 捕捉屏幕的一个矫形区域 */
public void captureImage() {
fullScreenImage = robot.createScreenCapture(new Rectangle(Toolkit
.getDefaultToolkit().getScreenSize()));
ImageIcon icon = new ImageIcon(fullScreenImage);
labFullScreenImage.setIcon(icon);
dialog.setVisible(true);
}
/** 得到捕捉后的BufferedImage */
public BufferedImage getPickedImage() {
return pickedImage;
}
/** 得到捕捉后的Icon */
public ImageIcon getPickedIcon() {
return new ImageIcon(getPickedImage());
}
/**
* 储存为一个文件,为PNG格式
*
* @deprecated replaced by saveAsPNG(File file)
**/
@Deprecated
public void saveToFile(File file) throws IOException {
ImageIO.write(getPickedImage(), defaultImageFormater, file);
}
/** 写入一个OutputStream */
public void write(OutputStream out) throws IOException {
ImageIO.write(getPickedImage(), defaultImageFormater, out);
}
// singleton design pattern
private static ScreenCapture defaultCapturer = new ScreenCapture();
private int x1, y1, x2, y2;
private int recX, recY, recH, recW; // 截取的图像
private boolean isFirstPoint = true;
private BackgroundImage labFullScreenImage = new BackgroundImage();
//private Label messageLabel = new Label("按任意键可退出。");
private Robot robot;
private BufferedImage fullScreenImage;
private BufferedImage pickedImage;
private String defaultImageFormater = "png";
private JDialog dialog = new JDialog();
}
/** 显示图片的Label */
class BackgroundImage extends JLabel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(x, y, w, h);
String area = w + " * " + h;
g.drawString(area, x + w / 2 - 15, y + h / 2);
g.drawLine(lineX, 0, lineX, getHeight());
g.drawLine(0, lineY, getWidth(), lineY);
}
public void drawRectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
h = height;
w = width;
repaint();
}
public void drawCross(int x, int y) {
lineX = x;
lineY = y;
repaint();
}
int lineX, lineY;
int x, y, h, w;
}

@ -0,0 +1,27 @@
This program uses the following libraries in accordance with the Apache License 2.0,
You can get the full text of Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0
--------------------------------------------------
JFoenix (8.0.4)
--------------------------------------------------
Copyright © JFoenix 2015-2017
https://github.com/jfoenixadmin/JFoenix
--------------------------------------------------
Apache Commons Codec (1.11)
--------------------------------------------------
Copyright © 2002-2020 The Apache Software Foundation
http://commons.apache.org/proper/commons-codec/
--------------------------------------------------
Gson (2.8.5)
--------------------------------------------------
Copyright 2008 Google Inc.
https://github.com/google/gson
--------------------------------------------------
OkHttp3 (4.2.2)
--------------------------------------------------
Copyright 2019 Square, Inc.
https://github.com/square/okhttp

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,86 @@
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.GushiciPaneController;
import me.lensferno.dogename.utils.HtmlRequseter;
public class Gushici {
private final String GUSHICI_API="https://v1.jinrishici.com/all.json";
String gushiciJSON = null;
private String getGushici() {
return HtmlRequseter.getHtml(GUSHICI_API,false);
}
public void showGushici(Pane rootPane, Label topBar){
new Thread(()->{
//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;
}
}
}

@ -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;
}
}
}

@ -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;
}
}

@ -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<ActionEvent> 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();
}
}

@ -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);
}
}
}

@ -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();
}
}

@ -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;
}
}

@ -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);
}
}
}

@ -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());
}
}
}

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: me.lensferno.dogename.Main

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="143.0" prefWidth="546.0" spacing="5.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<padding>
<Insets left="10.0" right="10.0" top="10.0" />
</padding>
<children>
<Label text="您可以自定义百度语音合成的API KEY和SEC KEY,而不必使用作者提供的信息。" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</Label>
<HBox alignment="CENTER_LEFT" prefHeight="40.0" prefWidth="200.0" spacing="5.0">
<children>
<Label text="API Key:">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
<HBox.margin>
<Insets />
</HBox.margin>
</Label>
<JFXTextField prefHeight="29.0" prefWidth="436.0" promptText="在此输入API Key">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXTextField>
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="40.0" prefWidth="200.0" spacing="5.0">
<children>
<Label text="Secret Key:">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
<HBox.margin>
<Insets />
</HBox.margin>
</Label>
<JFXTextField prefHeight="23.0" prefWidth="418.0" promptText="在此输入Secret Key">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXTextField>
</children>
</HBox>
</children>
</fx:root>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.*?>
<fx:root alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="380.0" prefWidth="794.0" spacing="15.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Text fx:id="contentText" strokeType="OUTSIDE" strokeWidth="0.0" text="“欲把西湖比西子,淡妆浓抹总相宜。”" textAlignment="CENTER" wrappingWidth="794.0">
<font>
<Font name="Microsoft YaHei Bold" size="30.0" />
</font>
</Text>
<Rectangle fill="#1f93ff41" height="58.0" stroke="BLACK" strokeType="INSIDE" strokeWidth="0.0" width="795.0" />
<Text fx:id="contentInfo" strokeType="OUTSIDE" strokeWidth="0.0" text="《饮湖上初晴后雨二首·其二》——苏轼" textAlignment="CENTER" wrappingWidth="794.0">
<font>
<Font name="Microsoft YaHei" size="16.0" />
</font>
</Text>
<Text fx:id="contentType" strokeType="OUTSIDE" strokeWidth="0.0" text="古诗文-山水-西湖" textAlignment="CENTER" wrappingWidth="794.0">
<font>
<Font name="Microsoft YaHei" size="16.0" />
</font>
</Text>
</children>
</fx:root>

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.layout.*?>
<?import com.jfoenix.controls.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.*?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="395.0" prefWidth="287.0" spacing="5.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<JFXListView fx:id="historyList" prefHeight="270.0" prefWidth="301.0" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="历史记录超过2000条时会自动清空列表重新记录">
<font>
<Font name="Microsoft YaHei" size="12.0" />
</font>
</Text>
<JFXTextField fx:id="searchBar" promptText="查找...">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXTextField>
<HBox prefHeight="29.0" prefWidth="259.0" spacing="5.0">
<children>
<JFXButton fx:id="previousBtn" onAction="#upSearch" text="上一个">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXButton>
<JFXButton fx:id="nextBtn" onAction="#downSearch" text="下一个">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXButton>
<JFXButton onAction="#clearHistory" text="全部清除">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
<padding>
<Insets left="14.0" right="14.0" top="14.0" />
</padding>
</fx:root>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.*?>
<fx:root alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="380.0" prefWidth="794.0" spacing="15.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Text fx:id="hitokotoContent" strokeType="OUTSIDE" strokeWidth="0.0" text="『我觉得在这里干尽坏事的玩家,都是些在现实世界中也烂到骨子里的家伙。』" textAlignment="CENTER" wrappingWidth="794.0">
<font>
<Font name="Microsoft YaHei Bold" size="30.0" />
</font>
</Text>
<Rectangle fill="#1f93ff41" height="58.0" stroke="BLACK" strokeType="INSIDE" strokeWidth="0.0" width="795.0" />
<Text fx:id="contentInfo" strokeType="OUTSIDE" strokeWidth="0.0" text="出自:刀剑神域  |  上传者:hitokoto" textAlignment="CENTER" wrappingWidth="794.0">
<font>
<Font name="Microsoft YaHei" size="16.0" />
</font>
</Text>
<Text fx:id="contentType" strokeType="OUTSIDE" strokeWidth="0.0" text="分类: 动画" textAlignment="CENTER" wrappingWidth="794.0">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</Text>
</children>
</fx:root>

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.paint.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<?import com.jfoenix.controls.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.*?>
<Pane fx:id="rootPane" prefHeight="711.0" prefWidth="1007.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="me.lensferno.dogename.controllers.MainInterfaceController">
<children>
<Pane fx:id="mainPane" prefHeight="710.0" prefWidth="1007.0">
<children>
<Label fx:id="chosen_1" alignment="CENTER" layoutX="194.0" layoutY="60.0" prefHeight="117.0" prefWidth="650.0" text="(´□`川)" textAlignment="CENTER" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="86.0" />
</font>
</Label>
<JFXButton layoutX="194.0" layoutY="551.0" onAction="#showProgramInfo" prefHeight="25.0" prefWidth="650.0" style="-fx-background-color: #F8F9F9;" text="不知所措?这里有使用帮助 &amp; 程序说明">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font></JFXButton>
<Label fx:id="chosen_2" alignment="CENTER" layoutX="194.0" layoutY="177.0" prefHeight="117.0" prefWidth="650.0" text="✋( ˙0˙)" textAlignment="CENTER" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="86.0" />
</font>
</Label>
<Label fx:id="topBar" alignment="TOP_CENTER" prefHeight="60.0" prefWidth="1007.0" text="富强 民主 文明 和谐 自由 平等 公正 法治 爱国 敬业 诚信 友善" textAlignment="CENTER" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</Label>
<ImageView fx:id="mainView" fitHeight="152.0" fitWidth="152.0" layoutX="841.0" layoutY="19.0" pickOnBounds="true" preserveRatio="true">
</ImageView>
<HBox alignment="CENTER" layoutX="194.0" layoutY="489.0" prefHeight="62.0" prefWidth="650.0" spacing="30.0">
<children>
<JFXRadioButton fx:id="nameChoose" layoutX="223.0" layoutY="508.0" selected="true" text="名字挑选法">
<font>
<Font name="Microsoft YaHei UI" size="17.0" />
</font>
</JFXRadioButton>
<JFXButton fx:id="showNameMangerButton" layoutX="358.0" layoutY="502.0" onAction="#showNameManger" prefHeight="36.0" prefWidth="92.0" ripplerFill="#00eafff7" text="名单管理">
<font>
<Font name="Microsoft YaHei UI" size="17.0" />
</font>
</JFXButton>
<Line endY="60.0" stroke="#00000068" strokeWidth="2.0" />
<JFXRadioButton fx:id="numbChoose" layoutX="540.0" layoutY="508.0" text="号码挑选法">
<font>
<Font name="Microsoft YaHei UI" size="17.0" />
</font>
</JFXRadioButton>
<JFXButton layoutX="698.0" layoutY="502.0" onAction="#showNunberSetting" prefHeight="36.0" prefWidth="92.0" ripplerFill="#00eafff7" text="调整数字">
<font>
<Font name="Microsoft YaHei UI" size="17.0" />
</font>
</JFXButton>
</children>
</HBox>
<HBox layoutX="194.0" layoutY="580.0" prefHeight="50.0" prefWidth="650.0">
<children>
<JFXButton fx:id="miniModeBtn" onAction="#miniMode" prefHeight="45.0" prefWidth="166.0" text="小窗模式">
<font>
<Font name="Microsoft YaHei" size="25.0" />
</font>
</JFXButton>
<JFXButton onAction="#showSettings" prefHeight="45.0" prefWidth="166.0" text="更多设置">
<font>
<Font name="Microsoft YaHei" size="25.0" />
</font>
</JFXButton>
<JFXButton fx:id="showHistoryBtn" onAction="#showHistory" prefHeight="45.0" prefWidth="166.0" text="历史记录">
<font>
<Font name="Microsoft YaHei" size="25.0" />
</font>
</JFXButton>
<JFXButton fx:id="anPaiBtn" onAction="#anPai" prefHeight="45.0" prefWidth="166.0" style="-fx-background-color: #D6EAF8;" text="安排一下">
<font>
<Font name="Microsoft YaHei" size="25.0" />
</font>
</JFXButton>
</children>
</HBox>
<JFXTextArea fx:id="message" editable="false" layoutX="194.0" layoutY="321.0" prefHeight="168.0" prefWidth="650.0">
<font>
<Font name="Microsoft YaHei" size="15.0" />
</font>
<cursor>
<Cursor fx:constant="DEFAULT" />
</cursor>
</JFXTextArea>
</children>
</Pane>
</children>
</Pane>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="134.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="me.lensferno.dogename.controllers.MiniPaneController">
<children>
<Label fx:id="chosenNameLabel" alignment="CENTER" prefHeight="68.0" prefWidth="300.0" text="(´□`川)" textAlignment="CENTER" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="48.0" />
</font>
</Label>
<HBox alignment="CENTER" prefHeight="67.0" prefWidth="405.0" spacing="20.0">
<children>
<JFXButton fx:id="miniModeBtn" onAction="#recoverMode" prefHeight="60.0" prefWidth="166.0" text="恢复">
<font>
<Font name="Microsoft YaHei" size="26.0" />
</font>
</JFXButton>
<JFXButton fx:id="anPaiBtn" onAction="#anPai" prefHeight="60.0" prefWidth="166.0" text="安排一下">
<font>
<Font name="Microsoft YaHei" size="26.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
</VBox>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXListView?>
<?import javafx.scene.layout.Pane?>
<Pane fx:id="namePane" prefHeight="196.0" prefWidth="279.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<JFXListView fx:id="nameList" editable="true" layoutX="1.0" prefHeight="193.0" prefWidth="278.0" styleClass="nameList" />
</children>
</Pane>

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="498.0" prefWidth="474.0" spacing="15.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<children>
<JFXListView fx:id="nameList" prefHeight="149.0" />
<JFXTextArea fx:id="inputName" focusColor="#0086ff" labelFloat="true" prefHeight="104.0" promptText="请输入要添加的名字,如需批量添加请一行一个名字。">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</JFXTextArea>
<HBox alignment="CENTER" prefHeight="39.0" prefWidth="454.0">
<children>
<JFXButton onAction="#addNameFromScreen" prefHeight="35.0" prefWidth="176.0" text="从屏幕上截取名字">
<HBox.margin>
<Insets />
</HBox.margin>
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
<JFXButton onAction="#copyTo" prefHeight="35.0" prefWidth="176.0" text="粘贴剪贴板内容">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
</children>
</HBox>
<HBox alignment="CENTER" spacing="5.0">
<children>
<JFXButton fx:id="deleteName" onAction="#deleteName" prefHeight="36.0" prefWidth="120.0" ripplerFill="RED" text="删除所选" textFill="RED">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
<JFXButton fx:id="deleteAll" onAction="#deleteAllName" prefHeight="36.0" prefWidth="120.0" ripplerFill="RED" text="删除所有" textFill="RED">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
<JFXButton onAction="#makeMass" prefHeight="28.0" prefWidth="120.0" ripplerFill="#4997fc" text="打乱顺序">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
</children>
<padding>
<Insets left="3.0" top="3.0" />
</padding>
</HBox>
<HBox alignment="CENTER" spacing="5.0">
<children>
<JFXButton onAction="#exoprtNameList" prefHeight="28.0" prefWidth="120.0" ripplerFill="#4997fc" text="备份">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
<JFXButton onAction="#importNameList" prefHeight="28.0" prefWidth="120.0" ripplerFill="#4997fc" text="恢复">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
<JFXButton fx:id="addName" onAction="#addName" prefHeight="36.0" prefWidth="120.0" ripplerFill="#4997fc" text="添加">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXButton>
</children>
<padding>
<Insets left="3.0" top="3.0" />
</padding>
</HBox>
</children>
</fx:root>

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.*?>
<fx:root alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="131.0" prefWidth="303.0" spacing="10.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="30.0" prefWidth="215.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="最小:">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</Text>
<JFXTextField fx:id="minValueField" labelFloat="true" prefHeight="23.0" prefWidth="141.0" text="0">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font></JFXTextField>
</children>
</HBox>
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="30.0" prefWidth="215.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="最大:">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</Text>
<JFXTextField fx:id="maxValueField" labelFloat="true" prefHeight="23.0" prefWidth="141.0" text="0">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font></JFXTextField>
</children>
</HBox>
</children>
</fx:root>

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXSpinner?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.*?>
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="566.0" prefWidth="499.0" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="me.lensferno.dogename.controllers.OcrPaneController">
<children>
<TextArea fx:id="ocrText" prefHeight="566.0" prefWidth="236.0" promptText="识别出的内容会在这里显示">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</TextArea>
<VBox alignment="TOP_CENTER" prefHeight="538.0" prefWidth="236.0" spacing="10.0">
<children>
<Pane>
<children>
<JFXSpinner fx:id="loadingSpinner" mouseTransparent="true" prefHeight="63.0" prefWidth="231.0" visible="false" />
<Text fx:id="statusText" layoutX="1.0" layoutY="15.0" strokeType="OUTSIDE" strokeWidth="0.0" wrappingWidth="236.0">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</Text>
</children>
</Pane>
<Line endX="236.0" stroke="#0000006d" strokeWidth="2.0" />
<JFXButton onAction="#addNew" prefHeight="40.0" prefWidth="205.0" text="截屏并开始识别">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXButton>
<JFXButton onAction="#copyText" prefHeight="40.0" prefWidth="205.0" text="复制内容">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXButton>
<Line endX="236.0" stroke="#0000006d" strokeWidth="2.0" />
<Label text="小提示:">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</Label>
<Label alignment="TOP_LEFT" prefHeight="67.0" prefWidth="236.0" text="1.点击“截屏并开始识别”可开始截取屏幕内容并开始识别,识别出来的文字会添加进左侧的文本框中。" textOverrun="CLIP" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</Label>
<Label alignment="TOP_LEFT" prefHeight="48.0" prefWidth="236.0" text="2.识别完成后请对右侧的识别内容进行修改,使得一行只有一个名字。" textOverrun="CLIP" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</Label>
<Label alignment="TOP_LEFT" prefHeight="50.0" prefWidth="236.0" text="3.确保正确后请将左侧的文字复制后粘贴到名字输入框中,以便添加名字。" textOverrun="CLIP" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</Label>
<Label alignment="TOP_LEFT" prefHeight="24.0" prefWidth="236.0" text="4.点击鼠标右键可退出截图。" textOverrun="CLIP" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</Label>
<Label text="注意:">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</Label>
<Label alignment="TOP_LEFT" prefHeight="24.0" prefWidth="236.0" text="    本功能需要联网使用" textAlignment="CENTER" textOverrun="CLIP" wrapText="true">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</Label>
</children>
</VBox>
</children>
<padding>
<Insets bottom="14.0" left="14.0" right="14.0" top="14.0" />
</padding>
</HBox>

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="459.0" prefWidth="692.0" spacing="10.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ImageView fx:id="dogeView" fitHeight="150.0" fitWidth="664.0" pickOnBounds="true" preserveRatio="true">
<cursor>
<Cursor fx:constant="NONE" />
</cursor></ImageView>
<JFXTextArea editable="false" focusColor="#0072ffbf" labelFloat="true" prefHeight="227.0" prefWidth="678.0" text="该程序以Google Material Design为界面风格,使用Java语言编写,是一个用来点名的家伙。&#10;这是一个开源软件,源代码可在https://github.com/lensferno/dogename查看和获取。&#10;(大更新基本上是不会有的了ヾ§  ̄▽)ゞ,等什么时候有空了再考虑吧(=´∇`=))&#10;&#10;&#10;---------------------------------------------------------------------------------------&#10;使用到的第三方库:&#10;JFoenix(8.0.4),UI界面库。&#10;Apache Commons Codec(1.11),用于Base64解码。&#10;Gson(2.8.5),用于Json数据的解析与生成。&#10;OkHttp3(4.2.2),用于语音部分的数据请求。&#10;gushici项目提供的古诗词接口和数据。&#10;“每日一句话”的数据来自一言&#10;本项目还使用了 百度AI SDK 来实现OCR功能。&#10;---------------------------------------------------------------------------------------&#10;About me:&#10; Github主页:https://github.com/lensferno&#10; 联系:lensferno@outlook.com  ulcch@foxmail.com&#10;---------------------------------------------------------------------------------------&#10;">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</JFXTextArea>
<HBox prefHeight="30.0" prefWidth="678.0" spacing="15.0">
<children>
<JFXButton buttonType="RAISED" onAction="#showHelp" prefHeight="30.0" prefWidth="150.0" ripplerFill="#006063" style="-fx-background-color: #B2EBF2;" text="使用帮助">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</JFXButton>
<JFXButton buttonType="RAISED" onAction="#viewCode" prefHeight="30.0" prefWidth="150.0" ripplerFill="#006063" style="-fx-background-color: #B2EBF2;" text="查看源代码">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</JFXButton>
<JFXButton buttonType="RAISED" onAction="#showLicense" prefHeight="30.0" prefWidth="150.0" ripplerFill="#006063" style="-fx-background-color: #B2EBF2;" text="开源协议(LGPL v3)">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</JFXButton>
<JFXButton buttonType="RAISED" onAction="#showLibLicense" prefHeight="30.0" prefWidth="150.0" ripplerFill="#006063" style="-fx-background-color: #B2EBF2;" text="其他开源许可">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
<padding>
<Insets left="14.0" top="14.0" />
</padding>
</fx:root>

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.shape.*?>
<?import com.jfoenix.controls.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.*?>
<fx:root prefHeight="360.0" prefWidth="593.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox prefHeight="50.0" prefWidth="592.0" spacing="10.0">
<children>
<Pane prefHeight="50.0" prefWidth="296.0">
<children>
<JFXRadioButton fx:id="ignoreOnce" layoutX="14.0" layoutY="14.0" selected="true" text="人人有份(跳过已点过的名字)">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXRadioButton>
</children>
</Pane>
<Pane prefHeight="50.0" prefWidth="296.0">
<children>
<JFXCheckBox fx:id="equalModeBtn" checkedColor="#079cd7" layoutX="14.0" layoutY="11.0" onAction="#equalBtnAction" prefHeight="28.0" prefWidth="162.0" text="记录已点过的名字" unCheckedColor="#13aecf">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXCheckBox>
</children>
</Pane>
</children>
</HBox>
<HBox prefHeight="50.0" prefWidth="592.0" spacing="10.0">
<children>
<Pane prefHeight="50.0" prefWidth="296.0">
<children>
<JFXRadioButton fx:id="chooseOnce" layoutX="14.0" layoutY="14.0" text="概率均分(不跳过已点过的名字)">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXRadioButton>
</children>
</Pane>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="286.0" spacing="1.0">
<children>
<JFXButton buttonType="RAISED" onAction="#clearIgnoreList" prefHeight="30.0" prefWidth="131.0" ripplerFill="#04d5ff" style="-fx-background-color: rgba(0,0,0,0.09);" text="清空记录" textFill="#1797e3">
<font>
<Font name="Microsoft YaHei" size="12.0" />
</font>
</JFXButton>
<JFXButton buttonType="RAISED" layoutX="15.0" layoutY="11.0" onAction="#showEqualMode" prefHeight="30.0" prefWidth="131.0" ripplerFill="#00e842" style="-fx-background-color: rgba(0,0,0,0.09);" text="选项说明" textFill="#294f65">
<font>
<Font name="Microsoft YaHei" size="12.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
</HBox>
<Line endX="592.0" />
<Pane prefHeight="50.0" prefWidth="592.0">
<children>
<JFXRadioButton fx:id="randomTimes" layoutX="14.0" layoutY="14.0" selected="true" text="挑选次数随机(100~250)">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXRadioButton>
</children>
</Pane>
<HBox prefHeight="50.0" prefWidth="592.0">
<children>
<JFXRadioButton fx:id="fixedTimes" text="挑选次数固定:">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</JFXRadioButton>
<JFXSlider fx:id="cycleTimesBar" max="200.0" min="3.0" prefHeight="18.0" prefWidth="386.0" showTickLabels="true" showTickMarks="true" value="120.0" />
</children>
<padding>
<Insets left="14.0" top="14.0" />
</padding>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
<Line endX="592.0" />
<HBox prefHeight="50.0" prefWidth="200.0">
<children>
<Label prefHeight="23.0" prefWidth="57.0" text="调速:">
<font>
<Font name="Microsoft YaHei" size="17.0" />
</font>
</Label>
<JFXSlider fx:id="speedBar" majorTickUnit="10.0" prefHeight="15.0" prefWidth="479.0" showTickLabels="true" showTickMarks="true" value="80.0" />
</children>
<padding>
<Insets left="14.0" top="14.0" />
</padding>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
<Line endX="592.0" />
<Pane prefHeight="50.0" prefWidth="593.0">
<children>
<JFXCheckBox fx:id="newAlgoBtn" checkedColor="#079cd7" layoutX="14.0" layoutY="14.0" selected="true" text="使用Java SecureRandom随机算法" textFill="#2c2424" unCheckedColor="#13aecf">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXCheckBox>
</children>
</Pane>
<HBox prefHeight="50.0" prefWidth="200.0" spacing="20.0">
<children>
<JFXCheckBox fx:id="showSayingBtn" checkedColor="#079cd7" prefHeight="31.0" prefWidth="188.0" selected="true" text="启动时展示一言/古诗词" textFill="#2c2424" unCheckedColor="#13aecf">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXCheckBox>
<JFXCheckBox fx:id="voicePlayBtn" checkedColor="#079cd7" prefHeight="31.0" prefWidth="82.0" selected="true" text="语音播报" textFill="#2c2424" unCheckedColor="#13aecf">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXCheckBox>
<JFXButton onAction="#showVoiceSettingsPane" prefHeight="31.0" prefWidth="76.0" style="-fx-background-color: rgba(0,0,0,0.09);" text="语音设置">
<font>
<Font name="Microsoft YaHei" size="14.0" />
</font>
</JFXButton>
</children>
<padding>
<Insets left="14.0" top="14.0" />
</padding>
</HBox>
</children>
</fx:root>

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXSlider?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="176.0" prefWidth="487.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="40.0" prefWidth="200.0" spacing="5.0">
<children>
<Label text="朗读人:">
<font>
<Font name="Microsoft YaHei" size="16.0" />
</font>
</Label>
<JFXComboBox fx:id="speakerSelectBar" prefHeight="23.0" prefWidth="138.0" style="-fx-font-family: Microsoft YaHei;" />
</children>
<padding>
<Insets left="10.0" />
</padding>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="40.0" prefWidth="200.0" spacing="5.0">
<children>
<Label text="语速:">
<font>
<Font name="Microsoft YaHei" size="16.0" />
</font>
</Label>
<JFXSlider fx:id="voiceSpeedBar" majorTickUnit="1.0" max="15.0" minorTickCount="1" prefHeight="14.0" prefWidth="395.0" showTickLabels="true" snapToTicks="true" value="5.0" />
</children>
<padding>
<Insets left="10.0" />
</padding>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="40.0" prefWidth="200.0" spacing="5.0">
<children>
<Label text="语调:">
<font>
<Font name="Microsoft YaHei" size="16.0" />
</font>
</Label>
<JFXSlider fx:id="intonationBar" majorTickUnit="1.0" max="15.0" minorTickCount="1" prefHeight="14.0" prefWidth="395.0" showTickLabels="true" snapToTicks="true" value="5.0" />
</children>
<padding>
<Insets left="10.0" />
</padding>
</HBox>
<Pane nodeOrientation="LEFT_TO_RIGHT" prefHeight="40.0" prefWidth="487.0">
<children>
<JFXButton layoutX="14.0" layoutY="9.0" onAction="#showAdvancedVoiceSettings" text="高级设置">
<font>
<Font name="Microsoft YaHei" size="13.0" />
</font>
</JFXButton>
</children>
</Pane>
</children>
</fx:root>
Loading…
Cancel
Save