From c22bd13ec08200cd044850fafc0f67dae50bf51e Mon Sep 17 00:00:00 2001
From: RTAkland <me@rtast.cn>
Date: Thu, 7 Nov 2024 19:42:03 +0800
Subject: [PATCH] feat: add more api operator

---
 README.md                                     |  22 ++-
 gradle.properties                             |   2 +-
 .../cn/rtast/rob/segment/BaseSegment.kt       |  22 ---
 .../rob/segment/InternalMessageSegment.kt     |   7 +
 .../cn/rtast/rob/segment/MessageSegment.kt    | 161 +++++++++++++++---
 .../cn/rtast/rob/util/ob/MessageChain.kt      |  29 +++-
 .../src/test/kotlin/test/MessageChainTest.kt  |  17 +-
 7 files changed, 205 insertions(+), 55 deletions(-)
 delete mode 100644 onebot/src/main/kotlin/cn/rtast/rob/segment/BaseSegment.kt

diff --git a/README.md b/README.md
index a0f5883..6b0eadb 100644
--- a/README.md
+++ b/README.md
@@ -105,17 +105,37 @@ fun main() {
 
 # 消息构造器
 
+## 链式调用构造消息
+
 > 框架支持使用链式调用的方式构造一个消息, 以下是一个简单的示例, 也可以直接使用字符串的形式发送
 
 ```kotlin
 val msgChain = MessageChain.Builder()
     .addAt(message.sender.userId)
     .addText(message.rawMessage)
-    .addNewLine(3)  // repeat 3 times: append 3 \n to end
+    .addNewLine(3)  // 添加3个换行符到末尾
     .build()
 this.sendGroupMessage(message.groupId, msgChain)
 ```
 
+## 操作符重载构造消息
+
+```kotlin
+fun main() {
+  // 可以直接对一个链式调用构造的消息使用操作符重载
+  val chain = MessageChain.Builder().addText("1").build() + Text("")
+  println(chain)
+  val operator = AT(3458671395) +
+          Text("114514") +
+          Image("https://example.com/example.png") +
+          Reply(114514L) +
+          Face(666) +
+          NewLine() +
+          "1919810"
+  println(operator)
+}
+```
+
 # 消息即对象
 
 > 你可以对一个消息对象执行某些操作例如 撤回(revoke/recall) 回复(reply)
diff --git a/gradle.properties b/gradle.properties
index 194cf05..49b828a 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,2 @@
 kotlin.code.style=official
-libVersion=2.4.1
\ No newline at end of file
+libVersion=2.4.2
\ No newline at end of file
diff --git a/onebot/src/main/kotlin/cn/rtast/rob/segment/BaseSegment.kt b/onebot/src/main/kotlin/cn/rtast/rob/segment/BaseSegment.kt
deleted file mode 100644
index f117716..0000000
--- a/onebot/src/main/kotlin/cn/rtast/rob/segment/BaseSegment.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright © 2024 RTAkland
- * Author: RTAkland
- * Date: 2024/9/2
- */
-
-
-package cn.rtast.rob.segment
-
-import cn.rtast.rob.enums.ArrayMessageType
-
-/**
- * 内部使用的Segment作为超类
- */
-internal interface InternalBaseSegment {
-    val type: ArrayMessageType
-}
-
-/**
- * 用户可以使用的Segment作为超类
- */
-interface Segment
\ No newline at end of file
diff --git a/onebot/src/main/kotlin/cn/rtast/rob/segment/InternalMessageSegment.kt b/onebot/src/main/kotlin/cn/rtast/rob/segment/InternalMessageSegment.kt
index eb2f362..fe13b96 100644
--- a/onebot/src/main/kotlin/cn/rtast/rob/segment/InternalMessageSegment.kt
+++ b/onebot/src/main/kotlin/cn/rtast/rob/segment/InternalMessageSegment.kt
@@ -10,6 +10,13 @@ package cn.rtast.rob.segment
 import cn.rtast.rob.enums.ArrayMessageType
 import cn.rtast.rob.enums.internal.ContactType
 
+/**
+ * 内部使用的Segment作为超类
+ */
+internal interface InternalBaseSegment {
+    val type: ArrayMessageType
+}
+
 internal data class IPlainText(
     val data: Data,
     override val type: ArrayMessageType = ArrayMessageType.text
diff --git a/onebot/src/main/kotlin/cn/rtast/rob/segment/MessageSegment.kt b/onebot/src/main/kotlin/cn/rtast/rob/segment/MessageSegment.kt
index 77d6ff1..e5f3577 100644
--- a/onebot/src/main/kotlin/cn/rtast/rob/segment/MessageSegment.kt
+++ b/onebot/src/main/kotlin/cn/rtast/rob/segment/MessageSegment.kt
@@ -11,38 +11,109 @@ import cn.rtast.rob.enums.MusicShareType
 import cn.rtast.rob.enums.PokeMessage
 import cn.rtast.rob.enums.QQFace
 
-data class Text(val text: String) : Segment
-data class AT(val qq: Long) : Segment
-data class Face(val id: Int) : Segment
-data class QFace(val id: QQFace) : Segment
-data class Image(val file: String, val base64: Boolean = false) : Segment
-data class Record(val file: String) : Segment
-data class Video(val file: String) : Segment
-data class Poke(val poke: PokeMessage) : Segment
-data class Reply(val id: Long) : Segment
-data class XML(val xml: String) : Segment
-data class FriendContact(val id: Long) : Segment
-data class GroupContact(val id: Long) : Segment
-data class JSON(val json: String) : Segment
-data class MusicShare(val type: MusicShareType, val id: String) : Segment
-class Rps : Segment
-class Dice : Segment
-class Shake : Segment
+/**
+ * 非内部类, Segment作为超类
+ */
+sealed class Segment
+
+/**
+ * 纯文本
+ */
+data class Text(val text: String) : Segment()
+
+/**
+ * AT某人
+ */
+data class AT(val qq: Long) : Segment()
+
+/**
+ * 表情但是使用整形来构造
+ */
+data class Face(val id: Int) : Segment()
+
+/**
+ * 表情但是用[QQFace]来构造
+ */
+data class QFace(val id: QQFace) : Segment()
+
+/**
+ * 图片
+ */
+data class Image(val file: String, val base64: Boolean = false) : Segment()
+
+/**
+ * 语音
+ */
+data class Record(val file: String) : Segment()
+
+/**
+ * 视频
+ */
+data class Video(val file: String) : Segment()
+
+/**
+ * 戳一戳(旧版)
+ */
+data class Poke(val poke: PokeMessage) : Segment()
+
+/**
+ * 回复
+ */
+data class Reply(val id: Long) : Segment()
+
+/**
+ * XML消息
+ */
+data class XML(val xml: String) : Segment()
+
+/**
+ * 好友推荐
+ */
+data class FriendContact(val id: Long) : Segment()
+
+/**
+ * 群聊推荐
+ */
+data class GroupContact(val id: Long) : Segment()
+
+/**
+ * JSON消息
+ */
+data class JSON(val json: String) : Segment()
+
+/**
+ * 消息分享
+ */
+data class MusicShare(val type: MusicShareType, val id: String) : Segment()
+
+/**
+ * 插入换行符
+ */
+data class NewLine(val times: Int = 1) : Segment()
+
+/**
+ * 链接分享
+ */
 data class Share(
     val url: String,
     val title: String,
     val content: String? = null,
     val image: String? = null
-) : Segment
-
+) : Segment()
 
+/**
+ * 位置分享
+ */
 data class Location(
     val lat: Double,
     val lon: Double,
     val title: String? = null,
     val content: String? = null,
-) : Segment
+) : Segment()
 
+/**
+ * 自定义音乐分享
+ */
 data class CustomMusicShare(
     val url: String,
     val audio: String,
@@ -50,4 +121,52 @@ data class CustomMusicShare(
     val content: String? = null,
     val image: String? = null,
     val type: String = "custom",
-) : Segment
\ No newline at end of file
+) : Segment()
+
+/**
+ * 剪刀石头布
+ */
+class Rps : Segment() {
+    override fun toString() = "Rps"
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Rps) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return javaClass.hashCode()
+    }
+}
+
+/**
+ * 骰子
+ */
+class Dice : Segment() {
+    override fun toString() = "Dice"
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Dice) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return javaClass.hashCode()
+    }
+}
+
+/**
+ * 屏震(旧版)
+ */
+class Shake : Segment() {
+    override fun toString() = "Shake"
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Shake) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return javaClass.hashCode()
+    }
+}
\ No newline at end of file
diff --git a/onebot/src/main/kotlin/cn/rtast/rob/util/ob/MessageChain.kt b/onebot/src/main/kotlin/cn/rtast/rob/util/ob/MessageChain.kt
index d97c2f8..1244016 100644
--- a/onebot/src/main/kotlin/cn/rtast/rob/util/ob/MessageChain.kt
+++ b/onebot/src/main/kotlin/cn/rtast/rob/util/ob/MessageChain.kt
@@ -41,6 +41,7 @@ import cn.rtast.rob.segment.InternalBaseSegment
 import cn.rtast.rob.segment.JSON
 import cn.rtast.rob.segment.Location
 import cn.rtast.rob.segment.MusicShare
+import cn.rtast.rob.segment.NewLine
 import cn.rtast.rob.segment.Poke
 import cn.rtast.rob.segment.QFace
 import cn.rtast.rob.segment.Record
@@ -182,13 +183,6 @@ operator fun MessageChain.plus(other: Any): MessageChain {
     return this.finalArrayMsgList.add(IPlainText(IPlainText.Data(other.toString()))).toMessageChain()
 }
 
-/**
- * 对一个构造好的[MessageChain]使用+操作符快速添加一个[IAT]类型的消息段
- */
-operator fun MessageChain.plus(other: Long): MessageChain {
-    return this.finalArrayMsgList.add(IAT(IAT.Data(other.toString()))).toMessageChain()
-}
-
 /**
  * 将一个手动构造的Segment拼接成一个MessageChain
  */
@@ -198,7 +192,6 @@ operator fun Segment.plus(other: Segment): MessageChain {
         is Text -> msg.addText(this.text)
         is AT -> msg.addAt(this.qq)
         is Face -> msg.addFace(this.id)
-        is QFace -> msg.addFace(this.id)
         is Image -> msg.addImage(this.file, base64)
         is Record -> msg.addRecord(this.file)
         is Video -> msg.addVideo(this.file)
@@ -215,6 +208,8 @@ operator fun Segment.plus(other: Segment): MessageChain {
         is Share -> msg.addShare(this.url, this.title, this.content, this.image)
         is Location -> msg.addLocation(this.lat, this.lon, this.title, this.content)
         is CustomMusicShare -> msg.addCustomMusicShare(this.url, this.audio, this.title, this.content, this.image)
+        is NewLine -> msg.addNewLine(this.times)
+        is QFace -> msg.addFace(this.id)
     }
     when (other) {
         is Text -> msg.addText(other.text)
@@ -236,6 +231,8 @@ operator fun Segment.plus(other: Segment): MessageChain {
         is Share -> msg.addShare(other.url, other.title, other.content, other.image)
         is Location -> msg.addLocation(other.lat, other.lon, other.title, other.content)
         is CustomMusicShare -> msg.addCustomMusicShare(other.url, other.audio, other.title, other.content, other.image)
+        is NewLine -> msg.addNewLine(other.times)
+        is QFace -> msg.addFace(other.id)
     }
     return msg.build()
 }
@@ -251,6 +248,20 @@ operator fun MessageChain.plus(segment: Segment): MessageChain {
     return newBuilder.build()
 }
 
+/**
+ * [Segment]+[String]拼接
+ */
+operator fun Segment.plus(other: String): MessageChain {
+    return MessageChain.Builder().addSegment(this).addText(other).build()
+}
+
+/**
+ * [String]+[Segment]拼接
+ */
+operator fun String.plus(other: Segment): MessageChain {
+    return MessageChain.Builder().addText(this).addSegment(other).build()
+}
+
 /**
  * 快速构造一个数组形式的消息链
  * 支持绝大部分的消息链(Segment)
@@ -505,6 +516,8 @@ class MessageChain internal constructor(arrayMessageList: MutableList<InternalBa
                 is Dice -> addDice()
                 is Shake -> addShake()
                 is Share -> addShare(segment.url, segment.title, segment.content, segment.image)
+                is NewLine -> addNewLine(segment.times)
+                is QFace -> addFace(segment.id)
                 is Location -> addLocation(
                     segment.lat.toDouble(),
                     segment.lon.toDouble(),
diff --git a/onebot/src/test/kotlin/test/MessageChainTest.kt b/onebot/src/test/kotlin/test/MessageChainTest.kt
index 279b2c9..1ef9a8c 100644
--- a/onebot/src/test/kotlin/test/MessageChainTest.kt
+++ b/onebot/src/test/kotlin/test/MessageChainTest.kt
@@ -7,12 +7,25 @@
 package test
 
 import cn.rtast.rob.segment.AT
+import cn.rtast.rob.segment.Face
+import cn.rtast.rob.segment.Image
+import cn.rtast.rob.segment.NewLine
+import cn.rtast.rob.segment.Reply
 import cn.rtast.rob.segment.Text
 import cn.rtast.rob.util.ob.MessageChain
 import cn.rtast.rob.util.ob.plus
 
 
 fun main() {
-    MessageChain.Builder().addText("1").build() + Text("")
-    println((AT(3458671395) + Text("") + Text("1111") + Text("1111")))
+    // 可以直接对一个链式调用构造的消息使用操作符重载
+    val chain = MessageChain.Builder().addText("1").build() + Text("")
+    println(chain)
+    val operator = AT(3458671395) +
+            Text("114514") +
+            Image("https://example.com/example.png") +
+            Reply(114514L) +
+            Face(666) +
+            NewLine() +
+            ""
+    println(operator)
 }