mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-20 17:04:45 +08:00
[core] Support friend group (#2113)
* feat: support friend group * remove unnecessary modifications * toByteArray2 * support friendGroup, with api dump * support rename, with api dump * modify as required * modify as required * reverse * doc * FriendGroups * api dump * modify as required * fix CI * FriendGroup sync notice * api dump * modify as required * immutable * add friends: ContactList in FriendGroup * more sync notice * modify log content * Change `FriendGroup.friends` to `Collection<Friend>` * Fix `FriendGroup.friends.isEmpty()` * modified as require, untested * del count and online count in info * change import * fix missing import * set @since 2.13 and modified as required * modified as required * modified as required * doc * change friendGroupId type to Int? * api dumped * change friendGroupId type to Int? * introduce null to friendGroupId * modified as required * chore * api dump * chore: remark * change int? to int * api dump * Update mirai-core-api/src/commonMain/kotlin/data/FriendGroups.kt Co-authored-by: Him188 <Him188@mamoe.net> * Move FriendGroup and FriendGroups to contact.friendgroup * Make `Friend.friendGroup` not null * add FriendGroups.default for default group * Redesign FriendGroup interface Co-authored-by: Karlatemp <kar@kasukusakura.com> Co-authored-by: Him188 <Him188@mamoe.net>
This commit is contained in:
parent
eb892da093
commit
fea1d28488
@ -15,6 +15,7 @@ public abstract interface class net/mamoe/mirai/Bot : kotlinx/coroutines/Corouti
|
|||||||
public abstract fun getConfiguration ()Lnet/mamoe/mirai/utils/BotConfiguration;
|
public abstract fun getConfiguration ()Lnet/mamoe/mirai/utils/BotConfiguration;
|
||||||
public abstract fun getEventChannel ()Lnet/mamoe/mirai/event/EventChannel;
|
public abstract fun getEventChannel ()Lnet/mamoe/mirai/event/EventChannel;
|
||||||
public fun getFriend (J)Lnet/mamoe/mirai/contact/Friend;
|
public fun getFriend (J)Lnet/mamoe/mirai/contact/Friend;
|
||||||
|
public abstract fun getFriendGroups ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroups;
|
||||||
public fun getFriendOrFail (J)Lnet/mamoe/mirai/contact/Friend;
|
public fun getFriendOrFail (J)Lnet/mamoe/mirai/contact/Friend;
|
||||||
public abstract fun getFriends ()Lnet/mamoe/mirai/contact/ContactList;
|
public abstract fun getFriends ()Lnet/mamoe/mirai/contact/ContactList;
|
||||||
public fun getGroup (J)Lnet/mamoe/mirai/contact/Group;
|
public fun getGroup (J)Lnet/mamoe/mirai/contact/Group;
|
||||||
@ -354,6 +355,7 @@ public abstract interface class net/mamoe/mirai/contact/FileSupported : net/mamo
|
|||||||
public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/User, net/mamoe/mirai/contact/roaming/RoamingSupported {
|
public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/User, net/mamoe/mirai/contact/roaming/RoamingSupported {
|
||||||
public fun delete ()V
|
public fun delete ()V
|
||||||
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public abstract fun getFriendGroup ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
public abstract fun getRemark ()Ljava/lang/String;
|
public abstract fun getRemark ()Ljava/lang/String;
|
||||||
public fun nudge ()Lnet/mamoe/mirai/message/action/FriendNudge;
|
public fun nudge ()Lnet/mamoe/mirai/message/action/FriendNudge;
|
||||||
public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
|
public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
|
||||||
@ -908,6 +910,27 @@ public abstract interface class net/mamoe/mirai/contact/file/RemoteFiles {
|
|||||||
public static synthetic fun uploadNewFile$suspendImpl (Lnet/mamoe/mirai/contact/file/RemoteFiles;Ljava/lang/String;Lnet/mamoe/mirai/utils/ExternalResource;Lnet/mamoe/mirai/utils/ProgressionCallback;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public static synthetic fun uploadNewFile$suspendImpl (Lnet/mamoe/mirai/contact/file/RemoteFiles;Ljava/lang/String;Lnet/mamoe/mirai/utils/ExternalResource;Lnet/mamoe/mirai/utils/ProgressionCallback;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroup {
|
||||||
|
public fun delete ()Z
|
||||||
|
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public abstract fun getCount ()I
|
||||||
|
public abstract fun getFriends ()Ljava/util/Collection;
|
||||||
|
public abstract fun getId ()I
|
||||||
|
public abstract fun getName ()Ljava/lang/String;
|
||||||
|
public fun moveIn (Lnet/mamoe/mirai/contact/Friend;)Z
|
||||||
|
public abstract fun moveIn (Lnet/mamoe/mirai/contact/Friend;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public fun renameTo (Ljava/lang/String;)Z
|
||||||
|
public abstract fun renameTo (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroups {
|
||||||
|
public abstract fun asCollection ()Ljava/util/Collection;
|
||||||
|
public fun create (Ljava/lang/String;)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
|
public abstract fun create (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public abstract fun get (I)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
|
public fun getDefault ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract interface class net/mamoe/mirai/contact/roaming/RoamingMessage {
|
public abstract interface class net/mamoe/mirai/contact/roaming/RoamingMessage {
|
||||||
public fun getBot ()Lnet/mamoe/mirai/Bot;
|
public fun getBot ()Lnet/mamoe/mirai/Bot;
|
||||||
public abstract fun getContact ()Lnet/mamoe/mirai/contact/Contact;
|
public abstract fun getContact ()Lnet/mamoe/mirai/contact/Contact;
|
||||||
@ -962,6 +985,7 @@ public abstract interface class net/mamoe/mirai/contact/roaming/RoamingSupported
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
|
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
|
||||||
|
public abstract fun getFriendGroupId ()I
|
||||||
public abstract fun getNick ()Ljava/lang/String;
|
public abstract fun getNick ()Ljava/lang/String;
|
||||||
public abstract fun getRemark ()Ljava/lang/String;
|
public abstract fun getRemark ()Ljava/lang/String;
|
||||||
public abstract fun getUin ()J
|
public abstract fun getUin ()J
|
||||||
@ -970,9 +994,11 @@ public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mira
|
|||||||
|
|
||||||
public class net/mamoe/mirai/data/FriendInfoImpl : net/mamoe/mirai/data/FriendInfo {
|
public class net/mamoe/mirai/data/FriendInfoImpl : net/mamoe/mirai/data/FriendInfo {
|
||||||
public fun <init> (JLjava/lang/String;Ljava/lang/String;)V
|
public fun <init> (JLjava/lang/String;Ljava/lang/String;)V
|
||||||
|
public fun getFriendGroupId ()I
|
||||||
public fun getNick ()Ljava/lang/String;
|
public fun getNick ()Ljava/lang/String;
|
||||||
public fun getRemark ()Ljava/lang/String;
|
public fun getRemark ()Ljava/lang/String;
|
||||||
public fun getUin ()J
|
public fun getUin ()J
|
||||||
|
public fun setFriendGroupId (I)V
|
||||||
public fun setNick (Ljava/lang/String;)V
|
public fun setNick (Ljava/lang/String;)V
|
||||||
public fun setRemark (Ljava/lang/String;)V
|
public fun setRemark (Ljava/lang/String;)V
|
||||||
}
|
}
|
||||||
@ -1688,6 +1714,7 @@ public abstract interface class net/mamoe/mirai/data/UserInfo {
|
|||||||
public abstract interface class net/mamoe/mirai/data/UserProfile {
|
public abstract interface class net/mamoe/mirai/data/UserProfile {
|
||||||
public abstract fun getAge ()I
|
public abstract fun getAge ()I
|
||||||
public abstract fun getEmail ()Ljava/lang/String;
|
public abstract fun getEmail ()Ljava/lang/String;
|
||||||
|
public abstract fun getFriendGroupId ()I
|
||||||
public abstract fun getNickname ()Ljava/lang/String;
|
public abstract fun getNickname ()Ljava/lang/String;
|
||||||
public abstract fun getQLevel ()I
|
public abstract fun getQLevel ()I
|
||||||
public abstract fun getSex ()Lnet/mamoe/mirai/data/UserProfile$Sex;
|
public abstract fun getSex ()Lnet/mamoe/mirai/data/UserProfile$Sex;
|
||||||
|
@ -15,6 +15,7 @@ public abstract interface class net/mamoe/mirai/Bot : kotlinx/coroutines/Corouti
|
|||||||
public abstract fun getConfiguration ()Lnet/mamoe/mirai/utils/BotConfiguration;
|
public abstract fun getConfiguration ()Lnet/mamoe/mirai/utils/BotConfiguration;
|
||||||
public abstract fun getEventChannel ()Lnet/mamoe/mirai/event/EventChannel;
|
public abstract fun getEventChannel ()Lnet/mamoe/mirai/event/EventChannel;
|
||||||
public fun getFriend (J)Lnet/mamoe/mirai/contact/Friend;
|
public fun getFriend (J)Lnet/mamoe/mirai/contact/Friend;
|
||||||
|
public abstract fun getFriendGroups ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroups;
|
||||||
public fun getFriendOrFail (J)Lnet/mamoe/mirai/contact/Friend;
|
public fun getFriendOrFail (J)Lnet/mamoe/mirai/contact/Friend;
|
||||||
public abstract fun getFriends ()Lnet/mamoe/mirai/contact/ContactList;
|
public abstract fun getFriends ()Lnet/mamoe/mirai/contact/ContactList;
|
||||||
public fun getGroup (J)Lnet/mamoe/mirai/contact/Group;
|
public fun getGroup (J)Lnet/mamoe/mirai/contact/Group;
|
||||||
@ -354,6 +355,7 @@ public abstract interface class net/mamoe/mirai/contact/FileSupported : net/mamo
|
|||||||
public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/User, net/mamoe/mirai/contact/roaming/RoamingSupported {
|
public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/User, net/mamoe/mirai/contact/roaming/RoamingSupported {
|
||||||
public fun delete ()V
|
public fun delete ()V
|
||||||
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public abstract fun getFriendGroup ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
public abstract fun getRemark ()Ljava/lang/String;
|
public abstract fun getRemark ()Ljava/lang/String;
|
||||||
public fun nudge ()Lnet/mamoe/mirai/message/action/FriendNudge;
|
public fun nudge ()Lnet/mamoe/mirai/message/action/FriendNudge;
|
||||||
public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
|
public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
|
||||||
@ -908,6 +910,27 @@ public abstract interface class net/mamoe/mirai/contact/file/RemoteFiles {
|
|||||||
public static synthetic fun uploadNewFile$suspendImpl (Lnet/mamoe/mirai/contact/file/RemoteFiles;Ljava/lang/String;Lnet/mamoe/mirai/utils/ExternalResource;Lnet/mamoe/mirai/utils/ProgressionCallback;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public static synthetic fun uploadNewFile$suspendImpl (Lnet/mamoe/mirai/contact/file/RemoteFiles;Ljava/lang/String;Lnet/mamoe/mirai/utils/ExternalResource;Lnet/mamoe/mirai/utils/ProgressionCallback;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroup {
|
||||||
|
public fun delete ()Z
|
||||||
|
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public abstract fun getCount ()I
|
||||||
|
public abstract fun getFriends ()Ljava/util/Collection;
|
||||||
|
public abstract fun getId ()I
|
||||||
|
public abstract fun getName ()Ljava/lang/String;
|
||||||
|
public fun moveIn (Lnet/mamoe/mirai/contact/Friend;)Z
|
||||||
|
public abstract fun moveIn (Lnet/mamoe/mirai/contact/Friend;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public fun renameTo (Ljava/lang/String;)Z
|
||||||
|
public abstract fun renameTo (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroups {
|
||||||
|
public abstract fun asCollection ()Ljava/util/Collection;
|
||||||
|
public fun create (Ljava/lang/String;)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
|
public abstract fun create (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
public abstract fun get (I)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
|
public fun getDefault ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract interface class net/mamoe/mirai/contact/roaming/RoamingMessage {
|
public abstract interface class net/mamoe/mirai/contact/roaming/RoamingMessage {
|
||||||
public fun getBot ()Lnet/mamoe/mirai/Bot;
|
public fun getBot ()Lnet/mamoe/mirai/Bot;
|
||||||
public abstract fun getContact ()Lnet/mamoe/mirai/contact/Contact;
|
public abstract fun getContact ()Lnet/mamoe/mirai/contact/Contact;
|
||||||
@ -962,6 +985,7 @@ public abstract interface class net/mamoe/mirai/contact/roaming/RoamingSupported
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
|
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
|
||||||
|
public abstract fun getFriendGroupId ()I
|
||||||
public abstract fun getNick ()Ljava/lang/String;
|
public abstract fun getNick ()Ljava/lang/String;
|
||||||
public abstract fun getRemark ()Ljava/lang/String;
|
public abstract fun getRemark ()Ljava/lang/String;
|
||||||
public abstract fun getUin ()J
|
public abstract fun getUin ()J
|
||||||
@ -970,9 +994,11 @@ public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mira
|
|||||||
|
|
||||||
public class net/mamoe/mirai/data/FriendInfoImpl : net/mamoe/mirai/data/FriendInfo {
|
public class net/mamoe/mirai/data/FriendInfoImpl : net/mamoe/mirai/data/FriendInfo {
|
||||||
public fun <init> (JLjava/lang/String;Ljava/lang/String;)V
|
public fun <init> (JLjava/lang/String;Ljava/lang/String;)V
|
||||||
|
public fun getFriendGroupId ()I
|
||||||
public fun getNick ()Ljava/lang/String;
|
public fun getNick ()Ljava/lang/String;
|
||||||
public fun getRemark ()Ljava/lang/String;
|
public fun getRemark ()Ljava/lang/String;
|
||||||
public fun getUin ()J
|
public fun getUin ()J
|
||||||
|
public fun setFriendGroupId (I)V
|
||||||
public fun setNick (Ljava/lang/String;)V
|
public fun setNick (Ljava/lang/String;)V
|
||||||
public fun setRemark (Ljava/lang/String;)V
|
public fun setRemark (Ljava/lang/String;)V
|
||||||
}
|
}
|
||||||
@ -1688,6 +1714,7 @@ public abstract interface class net/mamoe/mirai/data/UserInfo {
|
|||||||
public abstract interface class net/mamoe/mirai/data/UserProfile {
|
public abstract interface class net/mamoe/mirai/data/UserProfile {
|
||||||
public abstract fun getAge ()I
|
public abstract fun getAge ()I
|
||||||
public abstract fun getEmail ()Ljava/lang/String;
|
public abstract fun getEmail ()Ljava/lang/String;
|
||||||
|
public abstract fun getFriendGroupId ()I
|
||||||
public abstract fun getNickname ()Ljava/lang/String;
|
public abstract fun getNickname ()Ljava/lang/String;
|
||||||
public abstract fun getQLevel ()I
|
public abstract fun getQLevel ()I
|
||||||
public abstract fun getSex ()Lnet/mamoe/mirai/data/UserProfile$Sex;
|
public abstract fun getSex ()Lnet/mamoe/mirai/data/UserProfile$Sex;
|
||||||
|
@ -15,6 +15,7 @@ package net.mamoe.mirai
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||||
import net.mamoe.mirai.contact.*
|
import net.mamoe.mirai.contact.*
|
||||||
|
import net.mamoe.mirai.contact.friendgroup.FriendGroups
|
||||||
import net.mamoe.mirai.event.EventChannel
|
import net.mamoe.mirai.event.EventChannel
|
||||||
import net.mamoe.mirai.event.events.BotEvent
|
import net.mamoe.mirai.event.events.BotEvent
|
||||||
import net.mamoe.mirai.message.action.BotNudge
|
import net.mamoe.mirai.message.action.BotNudge
|
||||||
@ -112,6 +113,13 @@ public interface Bot : CoroutineScope, ContactOrBot, UserOrBot {
|
|||||||
*/
|
*/
|
||||||
public val friends: ContactList<Friend>
|
public val friends: ContactList<Friend>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全部的好友分组
|
||||||
|
*
|
||||||
|
* @since 2.13
|
||||||
|
*/
|
||||||
|
public val friendGroups: FriendGroups
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 以 [对方 QQ 号码][id] 获取一个好友对象, 在获取失败时返回 `null`.
|
* 以 [对方 QQ 号码][id] 获取一个好友对象, 在获取失败时返回 `null`.
|
||||||
|
@ -15,6 +15,7 @@ package net.mamoe.mirai.contact
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
|
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||||
import net.mamoe.mirai.contact.roaming.RoamingSupported
|
import net.mamoe.mirai.contact.roaming.RoamingSupported
|
||||||
import net.mamoe.mirai.event.events.*
|
import net.mamoe.mirai.event.events.*
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
@ -38,6 +39,14 @@ import net.mamoe.mirai.utils.NotStableForInheritance
|
|||||||
@NotStableForInheritance
|
@NotStableForInheritance
|
||||||
public interface Friend : User, CoroutineScope, AudioSupported, RoamingSupported {
|
public interface Friend : User, CoroutineScope, AudioSupported, RoamingSupported {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 该好友所在的好友分组
|
||||||
|
*
|
||||||
|
* @since 2.13
|
||||||
|
*/
|
||||||
|
public val friendGroup: FriendGroup
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 备注信息
|
* 备注信息
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.contact.friendgroup
|
||||||
|
|
||||||
|
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||||
|
import net.mamoe.mirai.contact.Friend
|
||||||
|
import net.mamoe.mirai.utils.NotStableForInheritance
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个好友分组.
|
||||||
|
* 可能同时存在多个相同[名称][name]的分组, 但是每个分组的 [id] 都是唯一的.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 要获取一个分组, 可使用 [get] 根据 [ID][FriendGroup.id] 获取, 或者使用 [asCollection] 获取全部分组列表.
|
||||||
|
* 也可以通过 [Friend.friendGroup] 获取一个好友所在的分组.
|
||||||
|
*
|
||||||
|
* 在每次登录会话中, [FriendGroup] 的实例是依据 [id] 唯一的. 存在于同一个分组中的多个好友的 [Friend.friendGroup] 会返回相同的 [FriendGroup] 实例.
|
||||||
|
* 但当 bot 重新登录后, 实例可能变化.
|
||||||
|
*
|
||||||
|
* @see FriendGroups
|
||||||
|
* @since 2.13
|
||||||
|
*/
|
||||||
|
@JvmBlockingBridge
|
||||||
|
@NotStableForInheritance
|
||||||
|
public interface FriendGroup {
|
||||||
|
/**
|
||||||
|
* 好友分组 ID
|
||||||
|
*/
|
||||||
|
public val id: Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 好友分组名
|
||||||
|
*/
|
||||||
|
public val name: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 好友分组内好友数量
|
||||||
|
*/
|
||||||
|
public val count: Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 属于本分组的好友集合
|
||||||
|
*/
|
||||||
|
public val friends: Collection<Friend>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更改好友分组名称.
|
||||||
|
*
|
||||||
|
* 允许存在同名分组.
|
||||||
|
* 当操作成时返回 `true`; 当分组不存在时返回 `false`; 如果因为其他原因造成的改名失败时会抛出 [IllegalStateException]
|
||||||
|
*/
|
||||||
|
public suspend fun renameTo(newName: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把一名好友移动至本分组内.
|
||||||
|
*
|
||||||
|
* 当远程分组不存在时会自动移动该好友到 ID 为 0 的默认好友分组.
|
||||||
|
* 当操作成功时返回 `true`; 当分组不存在 (如已经在远程被删除) 时返回 `false`; 因为其他原因移动不成功时抛出 [IllegalStateException].
|
||||||
|
*/
|
||||||
|
public suspend fun moveIn(friend: Friend): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除本分组.
|
||||||
|
*
|
||||||
|
* 删除后组内全部好友移动至 ID 为 0 的默认好友分组, 本分组的好友列表会被清空.
|
||||||
|
* 当操作成功时返回 `true`; 当分组不存在或试图删除 ID 为 0 的默认好友分组时返回 `false`;
|
||||||
|
* 因为其他原因删除不成功时抛出 [IllegalStateException].
|
||||||
|
*/
|
||||||
|
public suspend fun delete(): Boolean
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.contact.friendgroup
|
||||||
|
|
||||||
|
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||||
|
import net.mamoe.mirai.utils.NotStableForInheritance
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 好友分组列表 (管理器).
|
||||||
|
* 允许存在重复名称的分组, 因此依赖于 name 判断不可靠, 需要依赖 ID 判断.
|
||||||
|
*
|
||||||
|
* @see FriendGroup
|
||||||
|
* @since 2.13
|
||||||
|
*/
|
||||||
|
@JvmBlockingBridge
|
||||||
|
@NotStableForInheritance
|
||||||
|
public interface FriendGroups {
|
||||||
|
/**
|
||||||
|
* 获取 [ID][FriendGroup.id] 为 `0` 的默认分组 ("我的好友").
|
||||||
|
*/
|
||||||
|
public val default: FriendGroup get() = get(0) ?: error("Internal error: could not find FriendGroup with id = 0.")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新建一个好友分组.
|
||||||
|
*
|
||||||
|
* 允许名称重复, 当新建一个已存在名称的分组时, 服务器会返回一个拥有重复名字的新分组;
|
||||||
|
* 当因为其他原因创建不成功时抛出 [IllegalStateException].
|
||||||
|
*
|
||||||
|
* 提示: 要删除一个好友分组, 使用 [FriendGroup.delete].
|
||||||
|
*/
|
||||||
|
public suspend fun create(name: String): FriendGroup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定 ID 的好友分组, 不存在时返回 `null`
|
||||||
|
*/
|
||||||
|
public operator fun get(id: Int): FriendGroup?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取包含全部 [FriendGroup] 的 [Collection]. 返回的 [Collection] 只可读取.
|
||||||
|
*
|
||||||
|
* 此方法快速返回, 不会在调用时实例化新的 [Collection] 对象.
|
||||||
|
* 返回的 [Collection] 是对缓存的引用, 会随着服务器通知和机器人操作 (如 [create]) 变化.
|
||||||
|
*/
|
||||||
|
public fun asCollection(): Collection<FriendGroup>
|
||||||
|
}
|
@ -18,6 +18,8 @@ public interface FriendInfo : UserInfo {
|
|||||||
public override val nick: String
|
public override val nick: String
|
||||||
|
|
||||||
public override var remark: String
|
public override var remark: String
|
||||||
|
|
||||||
|
public val friendGroupId: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -32,4 +34,6 @@ public open class FriendInfoImpl(
|
|||||||
override val uin: Long,
|
override val uin: Long,
|
||||||
override var nick: String,
|
override var nick: String,
|
||||||
override var remark: String,
|
override var remark: String,
|
||||||
) : FriendInfo
|
) : FriendInfo {
|
||||||
|
override var friendGroupId: Int = 0
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
*
|
*
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
*
|
*
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.mamoe.mirai.data
|
package net.mamoe.mirai.data
|
||||||
@ -27,6 +27,13 @@ public interface UserProfile {
|
|||||||
public val qLevel: Int
|
public val qLevel: Int
|
||||||
public val sex: Sex
|
public val sex: Sex
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 好友分组 ID, 在非好友情况下或者位于默认分组情况下为 `0`
|
||||||
|
*
|
||||||
|
* @since 2.13
|
||||||
|
*/
|
||||||
|
public val friendGroupId: Int
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 个性签名
|
* 个性签名
|
||||||
*/
|
*/
|
||||||
|
@ -100,7 +100,7 @@ internal abstract class AbstractBot constructor(
|
|||||||
final override val strangers: ContactList<StrangerImpl> = ContactList()
|
final override val strangers: ContactList<StrangerImpl> = ContactList()
|
||||||
|
|
||||||
final override val asFriend: FriendImpl by lazy {
|
final override val asFriend: FriendImpl by lazy {
|
||||||
Mirai.newFriend(this, FriendInfoImpl(uin, "", "")).cast()
|
Mirai.newFriend(this, FriendInfoImpl(uin, "", "", 0)).cast()
|
||||||
} // nick is initialized later on login
|
} // nick is initialized later on login
|
||||||
final override val asStranger: StrangerImpl by lazy {
|
final override val asStranger: StrangerImpl by lazy {
|
||||||
Mirai.newStranger(this, StrangerInfoImpl(bot.id, bot.nick)).cast()
|
Mirai.newStranger(this, StrangerInfoImpl(bot.id, bot.nick)).cast()
|
||||||
|
@ -599,7 +599,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
|||||||
if (!accept) return
|
if (!accept) return
|
||||||
|
|
||||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||||
bot.friends.delegate.add(newFriend(bot, FriendInfoImpl(fromId, fromNick, "")))
|
bot.friends.delegate.add(newFriend(bot, FriendInfoImpl(fromId, fromNick, "", 0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun solveBotInvitedJoinGroupRequestEvent(
|
override suspend fun solveBotInvitedJoinGroupRequestEvent(
|
||||||
|
@ -16,6 +16,7 @@ import net.mamoe.mirai.event.broadcast
|
|||||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||||
import net.mamoe.mirai.event.events.BotOnlineEvent
|
import net.mamoe.mirai.event.events.BotOnlineEvent
|
||||||
import net.mamoe.mirai.event.events.BotReloginEvent
|
import net.mamoe.mirai.event.events.BotReloginEvent
|
||||||
|
import net.mamoe.mirai.internal.contact.friendgroup.FriendGroupsImpl
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentStorageDelegate
|
import net.mamoe.mirai.internal.network.component.ComponentStorageDelegate
|
||||||
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||||
@ -44,6 +45,7 @@ import net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor
|
|||||||
import net.mamoe.mirai.internal.network.notice.group.GroupNotificationProcessor
|
import net.mamoe.mirai.internal.network.notice.group.GroupNotificationProcessor
|
||||||
import net.mamoe.mirai.internal.network.notice.group.GroupOrMemberListNoticeProcessor
|
import net.mamoe.mirai.internal.network.notice.group.GroupOrMemberListNoticeProcessor
|
||||||
import net.mamoe.mirai.internal.network.notice.group.GroupRecallProcessor
|
import net.mamoe.mirai.internal.network.notice.group.GroupRecallProcessor
|
||||||
|
import net.mamoe.mirai.internal.network.notice.priv.FriendGroupNoticeProcessor
|
||||||
import net.mamoe.mirai.internal.network.notice.priv.FriendNoticeProcessor
|
import net.mamoe.mirai.internal.network.notice.priv.FriendNoticeProcessor
|
||||||
import net.mamoe.mirai.internal.network.notice.priv.OtherClientNoticeProcessor
|
import net.mamoe.mirai.internal.network.notice.priv.OtherClientNoticeProcessor
|
||||||
import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageProcessor
|
import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageProcessor
|
||||||
@ -71,6 +73,8 @@ internal open class QQAndroidBot constructor(
|
|||||||
configuration: BotConfiguration,
|
configuration: BotConfiguration,
|
||||||
) : AbstractBot(configuration, account.id) {
|
) : AbstractBot(configuration, account.id) {
|
||||||
override val bot: QQAndroidBot get() = this
|
override val bot: QQAndroidBot get() = this
|
||||||
|
override val friendGroups: FriendGroupsImpl by lazy { FriendGroupsImpl(this) }
|
||||||
|
|
||||||
val client get() = components[SsoProcessor].client
|
val client get() = components[SsoProcessor].client
|
||||||
|
|
||||||
override fun close(cause: Throwable?) {
|
override fun close(cause: Throwable?) {
|
||||||
@ -191,6 +195,7 @@ internal open class QQAndroidBot constructor(
|
|||||||
GroupOrMemberListNoticeProcessor(pipelineLogger.subLogger("GroupOrMemberListNoticeProcessor")),
|
GroupOrMemberListNoticeProcessor(pipelineLogger.subLogger("GroupOrMemberListNoticeProcessor")),
|
||||||
GroupMessageProcessor(pipelineLogger.subLogger("GroupMessageProcessor")),
|
GroupMessageProcessor(pipelineLogger.subLogger("GroupMessageProcessor")),
|
||||||
GroupNotificationProcessor(pipelineLogger.subLogger("GroupNotificationProcessor")),
|
GroupNotificationProcessor(pipelineLogger.subLogger("GroupNotificationProcessor")),
|
||||||
|
FriendGroupNoticeProcessor(pipelineLogger.subLogger("FriendGroupNoticeProcessor")),
|
||||||
PrivateMessageProcessor(),
|
PrivateMessageProcessor(),
|
||||||
OtherClientNoticeProcessor(),
|
OtherClientNoticeProcessor(),
|
||||||
GroupRecallProcessor(),
|
GroupRecallProcessor(),
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.internal.contact
|
package net.mamoe.mirai.internal.contact
|
||||||
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import io.ktor.utils.io.core.*
|
import io.ktor.utils.io.core.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import net.mamoe.mirai.LowLevelApi
|
import net.mamoe.mirai.LowLevelApi
|
||||||
import net.mamoe.mirai.contact.Friend
|
import net.mamoe.mirai.contact.Friend
|
||||||
|
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||||
import net.mamoe.mirai.contact.roaming.RoamingMessages
|
import net.mamoe.mirai.contact.roaming.RoamingMessages
|
||||||
import net.mamoe.mirai.event.broadcast
|
import net.mamoe.mirai.event.broadcast
|
||||||
import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
|
import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
|
||||||
@ -53,7 +53,8 @@ internal fun net.mamoe.mirai.internal.network.protocol.data.jce.FriendInfo.toMir
|
|||||||
FriendInfoImpl(
|
FriendInfoImpl(
|
||||||
friendUin,
|
friendUin,
|
||||||
nick,
|
nick,
|
||||||
remark
|
remark,
|
||||||
|
groupId.toInt(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalContracts::class)
|
@OptIn(ExperimentalContracts::class)
|
||||||
@ -83,6 +84,9 @@ internal class FriendImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val friendGroup: FriendGroup
|
||||||
|
get() = bot.friendGroups[info.friendGroupId] ?: bot.friendGroups[0]!!
|
||||||
|
|
||||||
private val messageProtocolStrategy: MessageProtocolStrategy<FriendImpl> = FriendMessageProtocolStrategy(this)
|
private val messageProtocolStrategy: MessageProtocolStrategy<FriendImpl> = FriendMessageProtocolStrategy(this)
|
||||||
|
|
||||||
override suspend fun delete() {
|
override suspend fun delete() {
|
||||||
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.contact.friendgroup
|
||||||
|
|
||||||
|
import net.mamoe.mirai.contact.Friend
|
||||||
|
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||||
|
import net.mamoe.mirai.internal.QQAndroidBot
|
||||||
|
import net.mamoe.mirai.internal.contact.FriendImpl
|
||||||
|
import net.mamoe.mirai.internal.contact.impl
|
||||||
|
import net.mamoe.mirai.internal.contact.info.FriendGroupInfo
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||||
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
internal inline fun FriendGroup.impl(): FriendGroupImpl {
|
||||||
|
contract {
|
||||||
|
returns() implies (this@impl is FriendGroupImpl)
|
||||||
|
}
|
||||||
|
check(this is FriendGroupImpl) { "A FriendGroup instance is not instance of FriendGroupImpl. Your instance: ${this::class.qualifiedName}" }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FriendGroupImpl constructor(
|
||||||
|
val bot: QQAndroidBot,
|
||||||
|
val info: FriendGroupInfo
|
||||||
|
) : FriendGroup {
|
||||||
|
override val id: Int by info::groupId
|
||||||
|
|
||||||
|
override var name: String by info::groupName
|
||||||
|
override val count: Int
|
||||||
|
get() = friends.size
|
||||||
|
override val friends: Collection<Friend> = object : AbstractCollection<Friend>() {
|
||||||
|
override val size: Int
|
||||||
|
get() = bot.friends.count { it.impl().info.friendGroupId == id }
|
||||||
|
|
||||||
|
private val delegateSequence = sequence<Friend> {
|
||||||
|
bot.friends.forEach { friend ->
|
||||||
|
friend.impl()
|
||||||
|
if (friend.info.friendGroupId == id) {
|
||||||
|
yield(friend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<Friend> = delegateSequence.iterator()
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean {
|
||||||
|
return bot.friends.none { it.impl().info.friendGroupId == id }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contains(element: Friend): Boolean {
|
||||||
|
if (element !is FriendImpl) return false
|
||||||
|
return element.info.friendGroupId == id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override suspend fun renameTo(newName: String): Boolean {
|
||||||
|
bot.network.sendAndExpect(FriendList.SetGroupReqPack.Rename(bot.client, newName, id)).let {
|
||||||
|
if (it.result.toInt() == 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
check(it.isSuccess) {
|
||||||
|
"Cannot rename friendGroup(id=$id) to $newName, code=${it.result.toInt()}, errStr=${it.errStr}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.groupName = newName
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun moveIn(friend: Friend): Boolean {
|
||||||
|
bot.network.sendAndExpect(FriendList.MoveGroupMemReqPack(bot.client, friend.id, id)).let {
|
||||||
|
check(it.isSuccess) {
|
||||||
|
"Cannot move friend to $this, code=${it.result.toInt()}, errStr=${it.errStr}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 因为 MoveGroupMemReqPack 协议在测试里如果移动到不存在的分组,他会自动移动好友到 id = 0 的默认好友分组然后返回 result = 0
|
||||||
|
val id = friend.queryProfile().friendGroupId
|
||||||
|
friend.impl().info.friendGroupId = id
|
||||||
|
if (id != this.id && id == 0) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun delete(): Boolean {
|
||||||
|
bot.network.sendAndExpect(FriendList.SetGroupReqPack.Delete(bot.client, id)).let {
|
||||||
|
if (it.result.toInt() == 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
check(it.isSuccess) {
|
||||||
|
"Cannot delete friendGroup, code=${it.result.toInt()}, errStr=${it.errStr}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
friends.forEach {
|
||||||
|
it.impl().info.friendGroupId = 0
|
||||||
|
}
|
||||||
|
bot.friendGroups.friendGroups.remove(this)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "FriendGroup(id=$id, name=$name)"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.contact.friendgroup
|
||||||
|
|
||||||
|
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||||
|
import net.mamoe.mirai.contact.friendgroup.FriendGroups
|
||||||
|
import net.mamoe.mirai.internal.QQAndroidBot
|
||||||
|
import net.mamoe.mirai.internal.contact.info.FriendGroupInfo
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||||
|
import net.mamoe.mirai.utils.ConcurrentLinkedDeque
|
||||||
|
import net.mamoe.mirai.utils.asImmutable
|
||||||
|
|
||||||
|
internal class FriendGroupsImpl(
|
||||||
|
val bot: QQAndroidBot
|
||||||
|
) : FriendGroups {
|
||||||
|
val friendGroups = ConcurrentLinkedDeque<FriendGroupImpl>()
|
||||||
|
private val friendGroupsImmutable by lazy { friendGroups.asImmutable() }
|
||||||
|
|
||||||
|
override suspend fun create(name: String): FriendGroup {
|
||||||
|
val resp = bot.network.sendAndExpect(FriendList.SetGroupReqPack.New(bot.client, name))
|
||||||
|
check(resp.isSuccess) {
|
||||||
|
"Cannot create friendGroup, code=${resp.result.toInt()}, errStr=${resp.errStr}"
|
||||||
|
}
|
||||||
|
return FriendGroupImpl(bot, FriendGroupInfo(resp.groupId, name)).apply { friendGroups.add(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(id: Int): FriendGroup? = friendGroups.firstOrNull { it.id == id }
|
||||||
|
|
||||||
|
override fun asCollection(): Collection<FriendGroup> = friendGroupsImmutable
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.contact.info
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class FriendGroupInfo(
|
||||||
|
val groupId: Int,
|
||||||
|
var groupName: String,
|
||||||
|
// val friendCount: Int,
|
||||||
|
// val onlineFriendCount: Int
|
||||||
|
)
|
@ -18,8 +18,9 @@ internal data class FriendInfoImpl(
|
|||||||
override val uin: Long,
|
override val uin: Long,
|
||||||
override var nick: String,
|
override var nick: String,
|
||||||
override var remark: String,
|
override var remark: String,
|
||||||
|
override var friendGroupId: Int
|
||||||
) : FriendInfo {
|
) : FriendInfo {
|
||||||
companion object {
|
companion object {
|
||||||
fun FriendInfo.impl() = if (this is FriendInfoImpl) this else FriendInfoImpl(uin, nick, remark)
|
fun FriendInfo.impl() = if (this is FriendInfoImpl) this else FriendInfoImpl(uin, nick, remark, friendGroupId)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,10 +23,8 @@ import net.mamoe.mirai.data.MemberInfo
|
|||||||
import net.mamoe.mirai.internal.QQAndroidBot
|
import net.mamoe.mirai.internal.QQAndroidBot
|
||||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||||
import net.mamoe.mirai.internal.contact.StrangerImpl
|
import net.mamoe.mirai.internal.contact.StrangerImpl
|
||||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
import net.mamoe.mirai.internal.contact.friendgroup.FriendGroupImpl
|
||||||
import net.mamoe.mirai.internal.contact.info.GroupInfoImpl
|
import net.mamoe.mirai.internal.contact.info.*
|
||||||
import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
|
|
||||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
|
|
||||||
import net.mamoe.mirai.internal.contact.toMiraiFriendInfo
|
import net.mamoe.mirai.internal.contact.toMiraiFriendInfo
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||||
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||||
@ -160,6 +158,38 @@ internal class ContactUpdaterImpl(
|
|||||||
return friendInfos
|
return friendInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun refreshFriendGroupList(): List<FriendGroupImpl> {
|
||||||
|
logger.info { "Start loading friendGroup list..." }
|
||||||
|
val friendGroupInfos = mutableListOf<FriendGroupImpl>()
|
||||||
|
|
||||||
|
var count = 0
|
||||||
|
var total: Short
|
||||||
|
while (true) {
|
||||||
|
val data = bot.network.sendAndExpect(
|
||||||
|
FriendList.GetFriendGroupList(bot.client, 0, 0, count, 150)
|
||||||
|
)
|
||||||
|
|
||||||
|
total = data.totoalGroupCount
|
||||||
|
|
||||||
|
for (jceInfo in data.groupList) {
|
||||||
|
friendGroupInfos.add(
|
||||||
|
FriendGroupImpl(
|
||||||
|
bot, FriendGroupInfo(
|
||||||
|
jceInfo.groupId.toInt(),
|
||||||
|
jceInfo.groupname
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
count += data.groupList.size
|
||||||
|
logger.verbose { "Loading friendGroup list: ${count}/${total}" }
|
||||||
|
if (count >= total) break
|
||||||
|
}
|
||||||
|
logger.info { "Successfully loaded friendGroup list: $count in total" }
|
||||||
|
return friendGroupInfos
|
||||||
|
}
|
||||||
|
|
||||||
val list = if (friendListCache?.isValid(registerResp) == true) {
|
val list = if (friendListCache?.isValid(registerResp) == true) {
|
||||||
val list = friendListCache.list
|
val list = friendListCache.list
|
||||||
logger.info { "Loaded ${list.size} friends from local cache." }
|
logger.info { "Loaded ${list.size} friends from local cache." }
|
||||||
@ -178,11 +208,13 @@ internal class ContactUpdaterImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bot.friendGroups.friendGroups.clear()
|
||||||
|
bot.friendGroups.friendGroups.addAll(refreshFriendGroupList())
|
||||||
|
|
||||||
for (friendInfoImpl in list) {
|
for (friendInfoImpl in list) {
|
||||||
bot.addNewFriendAndRemoveStranger(friendInfoImpl)
|
bot.addNewFriendAndRemoveStranger(friendInfoImpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
initFriendOk = true
|
initFriendOk = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.network.notice.priv
|
||||||
|
|
||||||
|
import net.mamoe.mirai.internal.contact.friendgroup.FriendGroupImpl
|
||||||
|
import net.mamoe.mirai.internal.contact.friendgroup.impl
|
||||||
|
import net.mamoe.mirai.internal.contact.impl
|
||||||
|
import net.mamoe.mirai.internal.contact.info.FriendGroupInfo
|
||||||
|
import net.mamoe.mirai.internal.network.components.MixedNoticeProcessor
|
||||||
|
import net.mamoe.mirai.internal.network.components.NoticePipelineContext
|
||||||
|
import net.mamoe.mirai.internal.network.notice.NewContactSupport
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27
|
||||||
|
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||||
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
import net.mamoe.mirai.utils.context
|
||||||
|
import net.mamoe.mirai.utils.error
|
||||||
|
import net.mamoe.mirai.utils.warning
|
||||||
|
|
||||||
|
internal class FriendGroupNoticeProcessor(
|
||||||
|
private val logger: MiraiLogger,
|
||||||
|
) : MixedNoticeProcessor(), NewContactSupport {
|
||||||
|
|
||||||
|
override suspend fun NoticePipelineContext.processImpl(data: MsgType0x210) = data.context {
|
||||||
|
when (data.uSubMsgType) {
|
||||||
|
0x27L -> {
|
||||||
|
val body = vProtobuf.loadAs(Submsgtype0x27.SubMsgType0x27.SubMsgType0x27MsgBody.serializer())
|
||||||
|
for (msgModInfo in body.msgModInfos) {
|
||||||
|
markAsConsumed(msgModInfo)
|
||||||
|
when {
|
||||||
|
msgModInfo.msgModFriendGroup != null -> handleFriendGroupChanged(
|
||||||
|
msgModInfo.msgModFriendGroup, logger
|
||||||
|
)
|
||||||
|
msgModInfo.msgModGroupName != null -> handleFriendGroupNameChanged(
|
||||||
|
msgModInfo.msgModGroupName, logger
|
||||||
|
)
|
||||||
|
msgModInfo.msgDelGroup != null -> handleDelGroup(msgModInfo.msgDelGroup, logger)
|
||||||
|
msgModInfo.msgAddGroup != null -> handleAddGroup(msgModInfo.msgAddGroup)
|
||||||
|
else -> markNotConsumed(msgModInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NoticePipelineContext.handleAddGroup(
|
||||||
|
addGroup: Submsgtype0x27.SubMsgType0x27.AddGroup
|
||||||
|
) {
|
||||||
|
bot.friendGroups.friendGroups.add(
|
||||||
|
FriendGroupImpl(
|
||||||
|
bot,
|
||||||
|
FriendGroupInfo(addGroup.groupid, addGroup.groupname.decodeToString())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NoticePipelineContext.handleDelGroup(
|
||||||
|
delGroup: Submsgtype0x27.SubMsgType0x27.DelGroup, logger: MiraiLogger
|
||||||
|
) {
|
||||||
|
bot.friendGroups[delGroup.groupid]?.let { friendGroup ->
|
||||||
|
friendGroup.friends.forEach {
|
||||||
|
it.impl().info.friendGroupId = 0
|
||||||
|
}
|
||||||
|
bot.friendGroups.friendGroups.remove(friendGroup)
|
||||||
|
} ?: let {
|
||||||
|
logger.warning { "Detected friendGroup(id=${delGroup.groupid}) was removed but it isn't available in bot's friendGroups list" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NoticePipelineContext.handleFriendGroupNameChanged(
|
||||||
|
modFriendGroup: Submsgtype0x27.SubMsgType0x27.ModGroupName, logger: MiraiLogger
|
||||||
|
) {
|
||||||
|
bot.friendGroups[modFriendGroup.groupid]?.let {
|
||||||
|
it.impl().name = modFriendGroup.groupname.decodeToString()
|
||||||
|
} ?: let {
|
||||||
|
logger.warning { "Detected friendGroup(id=${modFriendGroup.groupid}) was renamed but it cannot be found in bot's friendGroups list" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NoticePipelineContext.handleFriendGroupChanged(
|
||||||
|
modFriendGroup: Submsgtype0x27.SubMsgType0x27.ModFriendGroup,
|
||||||
|
logger: MiraiLogger
|
||||||
|
) {
|
||||||
|
modFriendGroup.msgFrdGroup.forEach { body ->
|
||||||
|
val friend = bot.getFriend(body.fuin) ?: let {
|
||||||
|
logger.error { "Detected friend(id=${body.fuin}) was moved to friendGroup(id=${body.uint32NewGroupId}) but friend not found in bot's friends list" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (friend.impl().info.friendGroupId == body.uint32NewGroupId.first()) return@forEach
|
||||||
|
friend.info.friendGroupId = body.uint32NewGroupId.first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -264,6 +264,7 @@ internal class FriendNoticeProcessor(
|
|||||||
uin = body.msgAddFrdNotify.fuin,
|
uin = body.msgAddFrdNotify.fuin,
|
||||||
nick = body.msgAddFrdNotify.fuinNick,
|
nick = body.msgAddFrdNotify.fuinNick,
|
||||||
remark = "",
|
remark = "",
|
||||||
|
friendGroupId = 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
val removed = bot.removeStranger(info.uin)
|
val removed = bot.removeStranger(info.uin)
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.network.protocol.data.jce
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||||
|
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
||||||
|
import kotlin.jvm.JvmField
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal class MovGroupMemReq(
|
||||||
|
@JvmField @TarsId(0) val uin: Long = 0L,
|
||||||
|
@JvmField @TarsId(1) val reqtype: Byte = 0,
|
||||||
|
@JvmField @TarsId(2) val vecBody: ByteArray? = null
|
||||||
|
) : JceStruct
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal class MovGroupMemResp(
|
||||||
|
@JvmField @TarsId(0) val uin: Long = 0L,
|
||||||
|
@JvmField @TarsId(1) val reqtype: Byte = 0,
|
||||||
|
@JvmField @TarsId(2) val result: Byte = 0,
|
||||||
|
@JvmField @TarsId(3) val errorString: String = ""
|
||||||
|
) : JceStruct
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.network.protocol.data.jce
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||||
|
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
||||||
|
import kotlin.jvm.JvmField
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal class SetGroupReq(
|
||||||
|
@JvmField @TarsId(0) val reqtype: Int = 0,
|
||||||
|
@JvmField @TarsId(1) val uin: Long = 0L,
|
||||||
|
@JvmField @TarsId(2) val vecBody: ByteArray? = null
|
||||||
|
) : JceStruct
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal class SetGroupResp(
|
||||||
|
@JvmField @TarsId(0) val reqtype: Byte = 0,
|
||||||
|
@JvmField @TarsId(1) val result: Byte = 0,
|
||||||
|
@JvmField @TarsId(2) val vecBody: ByteArray? = null,
|
||||||
|
@JvmField @TarsId(3) val errorString: String = ""
|
||||||
|
) : JceStruct
|
@ -144,6 +144,8 @@ internal object KnownPacketFactories {
|
|||||||
FriendList.DelFriend,
|
FriendList.DelFriend,
|
||||||
FriendList.GetTroopListSimplify,
|
FriendList.GetTroopListSimplify,
|
||||||
FriendList.GetTroopMemberList,
|
FriendList.GetTroopMemberList,
|
||||||
|
FriendList.SetGroupReqPack,
|
||||||
|
FriendList.MoveGroupMemReqPack,
|
||||||
ImgStore.GroupPicUp,
|
ImgStore.GroupPicUp,
|
||||||
PttStore.GroupPttUp,
|
PttStore.GroupPttUp,
|
||||||
PttStore.GroupPttDown,
|
PttStore.GroupPttDown,
|
||||||
|
@ -20,11 +20,9 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.Vec0xd50
|
|||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Vec0xd6b
|
import net.mamoe.mirai.internal.network.protocol.data.proto.Vec0xd6b
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
|
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
|
import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.jceRequestSBuffer
|
import net.mamoe.mirai.internal.utils.io.serialization.*
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.readUniPacket
|
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.writeJceStruct
|
|
||||||
import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY
|
import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY
|
||||||
|
import net.mamoe.mirai.utils.toByteArray
|
||||||
|
|
||||||
|
|
||||||
internal class FriendList {
|
internal class FriendList {
|
||||||
@ -163,7 +161,10 @@ internal class FriendList {
|
|||||||
class Response(
|
class Response(
|
||||||
val selfInfo: FriendInfo?,
|
val selfInfo: FriendInfo?,
|
||||||
val totalFriendCount: Short,
|
val totalFriendCount: Short,
|
||||||
val friendList: List<FriendInfo>
|
val friendList: List<FriendInfo>,
|
||||||
|
// for FriendGroup
|
||||||
|
val groupList: List<GroupInfo>,
|
||||||
|
val totoalGroupCount: Short
|
||||||
) : Packet {
|
) : Packet {
|
||||||
override fun toString(): String = "FriendList.GetFriendGroupList.Response"
|
override fun toString(): String = "FriendList.GetFriendGroupList.Response"
|
||||||
}
|
}
|
||||||
@ -177,7 +178,9 @@ internal class FriendList {
|
|||||||
return Response(
|
return Response(
|
||||||
res.stSelfInfo,
|
res.stSelfInfo,
|
||||||
res.totoalFriendCount,
|
res.totoalFriendCount,
|
||||||
res.vecFriendInfo.orEmpty()
|
res.vecFriendInfo.orEmpty(),
|
||||||
|
res.vecGroupInfo.orEmpty(),
|
||||||
|
res.totoalGroupCount ?: -1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +250,7 @@ internal class FriendList {
|
|||||||
GetFriendListReq.serializer(),
|
GetFriendListReq.serializer(),
|
||||||
GetFriendListReq(
|
GetFriendListReq(
|
||||||
reqtype = 3,
|
reqtype = 3,
|
||||||
ifReflush = if (friendListStartIndex <= 0) {
|
ifReflush = if (friendListStartIndex + groupListStartIndex <= 0) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
1
|
1
|
||||||
@ -285,4 +288,118 @@ internal class FriendList {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for FriendGroup
|
||||||
|
internal object SetGroupReqPack : OutgoingPacketFactory<SetGroupReqPack.Response>("friendlist.SetGroupReq") {
|
||||||
|
class Response(
|
||||||
|
// Success: result == 0x00
|
||||||
|
val result: Byte,
|
||||||
|
val errStr: String,
|
||||||
|
// groupId for delete
|
||||||
|
val groupId: Int,
|
||||||
|
val isSuccess: Boolean = result.toInt() == 0
|
||||||
|
) : Packet {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "SetGroupResp(isSuccess=$isSuccess,resultCode=$result, errString=$errStr, groupId=$groupId)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
|
val pack = this.readUniPacket(SetGroupResp.serializer())
|
||||||
|
return if (pack.result.toInt() == 0) {
|
||||||
|
Response(pack.result, pack.errorString, pack.vecBody?.get(8)?.toInt() ?: -1)
|
||||||
|
} else {
|
||||||
|
Response(pack.result, pack.errorString, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object New {
|
||||||
|
operator fun invoke(
|
||||||
|
client: QQAndroidClient, groupName: String
|
||||||
|
) = buildOutgoingUniPacket(client) {
|
||||||
|
val arr = groupName.toByteArray()
|
||||||
|
// maybe is constant
|
||||||
|
val constant: Byte = 0x01
|
||||||
|
writeJceRequestPacket(
|
||||||
|
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||||
|
funcName = "SetGroupReq",
|
||||||
|
serializer = SetGroupReq.serializer(),
|
||||||
|
body = SetGroupReq(0, client.uin, byteArrayOf(constant, arr.size.toByte()) + arr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Rename {
|
||||||
|
operator fun invoke(client: QQAndroidClient, newName: String, id: Int) = buildOutgoingUniPacket(client) {
|
||||||
|
val arr = newName.toByteArray()
|
||||||
|
writeJceRequestPacket(
|
||||||
|
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||||
|
funcName = "SetGroupReq",
|
||||||
|
serializer = SetGroupReq.serializer(),
|
||||||
|
body = SetGroupReq(1, client.uin, byteArrayOf(id.toByte(), arr.size.toByte()) + arr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Delete {
|
||||||
|
operator fun invoke(client: QQAndroidClient, id: Int) = buildOutgoingUniPacket(client) {
|
||||||
|
writeJceRequestPacket(
|
||||||
|
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||||
|
funcName = "SetGroupReq",
|
||||||
|
serializer = SetGroupReq.serializer(),
|
||||||
|
body = SetGroupReq(2, client.uin, byteArrayOf(id.toByte()))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for FriendGroup
|
||||||
|
internal object MoveGroupMemReqPack :
|
||||||
|
OutgoingPacketFactory<MoveGroupMemReqPack.Response>("friendlist.MovGroupMemReq") {
|
||||||
|
private fun Long.toByteArray2(): ByteArray {
|
||||||
|
val arr = this.toByteArray()
|
||||||
|
val index = arr.indexOfFirst { it.toInt() != 0 }
|
||||||
|
return arr.sliceArray(index until arr.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不成功会自动移动到id = 0的默认好友分组, result 还是会返回0
|
||||||
|
class Response(
|
||||||
|
// Success: result == 0x00
|
||||||
|
val result: Byte,
|
||||||
|
val errStr: String,
|
||||||
|
val isSuccess: Boolean = result.toInt() == 0
|
||||||
|
) : Packet {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "MoveGroupMemReq(isSuccess=$isSuccess,resultCode=$result, errString=$errStr)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
|
val pack = this.readUniPacket(MovGroupMemResp.serializer())
|
||||||
|
return Response(pack.result, pack.errorString)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(
|
||||||
|
client: QQAndroidClient,
|
||||||
|
// friend id
|
||||||
|
id: Long,
|
||||||
|
// friend group id
|
||||||
|
groupId: Int
|
||||||
|
) = buildOutgoingUniPacket(client) {
|
||||||
|
writeJceRequestPacket(
|
||||||
|
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||||
|
funcName = "MovGroupMemReq",
|
||||||
|
serializer = MovGroupMemReq.serializer(),
|
||||||
|
body = MovGroupMemReq(
|
||||||
|
client.uin,
|
||||||
|
0,
|
||||||
|
byteArrayOf(
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
(id.toByteArray2().size + 1).toByte()
|
||||||
|
) + id.toByteArray2() + byteArrayOf(groupId.toByte(), 0x00, 0x00)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,10 @@ internal data class UserProfileImpl(
|
|||||||
override val qLevel: Int,
|
override val qLevel: Int,
|
||||||
override val sex: UserProfile.Sex,
|
override val sex: UserProfile.Sex,
|
||||||
override val sign: String,
|
override val sign: String,
|
||||||
|
override val friendGroupId: Int,
|
||||||
) : Packet, UserProfile {
|
) : Packet, UserProfile {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "UserProfile(nickname=$nickname, email=$email, age=$age, qLevel=$qLevel, sex=$sex, sign=$sign)"
|
return "UserProfile(nickname=$nickname, email=$email, age=$age, qLevel=$qLevel, sex=$sex, sign=$sign, friendGroupId=$friendGroupId)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +119,8 @@ internal object SummaryCard {
|
|||||||
1 -> UserProfile.Sex.FEMALE
|
1 -> UserProfile.Sex.FEMALE
|
||||||
else -> UserProfile.Sex.UNKNOWN
|
else -> UserProfile.Sex.UNKNOWN
|
||||||
},
|
},
|
||||||
sign = sign
|
sign = sign,
|
||||||
|
friendGroupId = response.uFriendGroupId?.toInt() ?: 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,8 +120,8 @@ internal interface GroupExtensions {
|
|||||||
friends.delegate.add(friend)
|
friends.delegate.add(friend)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Bot.addFriend(id: Long, nick: String = "friend$id", remark: String = ""): FriendImpl {
|
fun Bot.addFriend(id: Long, nick: String = "friend$id", remark: String = "", friendGroupId: Int = 0): FriendImpl {
|
||||||
return FriendImpl(bot.cast(), bot.coroutineContext, FriendInfoImpl(id, nick, remark)).also {
|
return FriendImpl(bot.cast(), bot.coroutineContext, FriendInfoImpl(id, nick, remark, friendGroupId)).also {
|
||||||
friends.delegate.add(it)
|
friends.delegate.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user