@@ -1,4 +1,6 @@ | |||||
#pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
using System; | |||||
namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
{ | { | ||||
public class ModifyPresenceParams | public class ModifyPresenceParams | ||||
@@ -5,6 +5,7 @@ | |||||
Unknown, | Unknown, | ||||
Online, | Online, | ||||
Idle, | Idle, | ||||
AFK, | |||||
DoNotDisturb, | DoNotDisturb, | ||||
Invisible, | Invisible, | ||||
Offline | Offline | ||||
@@ -38,6 +38,7 @@ namespace Discord.Net.Converters | |||||
writer.WriteValue("online"); | writer.WriteValue("online"); | ||||
break; | break; | ||||
case UserStatus.Idle: | case UserStatus.Idle: | ||||
case UserStatus.AFK: | |||||
writer.WriteValue("idle"); | writer.WriteValue("idle"); | ||||
break; | break; | ||||
case UserStatus.DoNotDisturb: | case UserStatus.DoNotDisturb: | ||||
@@ -212,12 +212,14 @@ namespace Discord.API | |||||
options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
await SendGatewayAsync(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false); | await SendGatewayAsync(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false); | ||||
} | } | ||||
public async Task SendStatusUpdateAsync(long? idleSince, Game game, RequestOptions options = null) | |||||
public async Task SendStatusUpdateAsync(UserStatus status, bool isAFK, long? since, Game game, RequestOptions options = null) | |||||
{ | { | ||||
options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
var args = new StatusUpdateParams | var args = new StatusUpdateParams | ||||
{ | { | ||||
IdleSince = idleSince, | |||||
Status = status, | |||||
IdleSince = since, | |||||
IsAFK = isAFK, | |||||
Game = game | Game = game | ||||
}; | }; | ||||
await SendGatewayAsync(GatewayOpCode.StatusUpdate, args, options: options).ConfigureAwait(false); | await SendGatewayAsync(GatewayOpCode.StatusUpdate, args, options: options).ConfigureAwait(false); | ||||
@@ -6,8 +6,12 @@ namespace Discord.API.Gateway | |||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)] | [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | ||||
public class StatusUpdateParams | public class StatusUpdateParams | ||||
{ | { | ||||
[JsonProperty("idle_since"), Int53] | |||||
[JsonProperty("status")] | |||||
public UserStatus Status { get; set; } | |||||
[JsonProperty("since"), Int53] | |||||
public long? IdleSince { get; set; } | public long? IdleSince { get; set; } | ||||
[JsonProperty("afk")] | |||||
public bool IsAFK { get; set; } | |||||
[JsonProperty("game")] | [JsonProperty("game")] | ||||
public Game Game { get; set; } | public Game Game { get; set; } | ||||
} | } | ||||
@@ -376,7 +376,7 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
var user = SocketGlobalUser.Create(this, state, model); | var user = SocketGlobalUser.Create(this, state, model); | ||||
user.GlobalUser.AddRef(); | user.GlobalUser.AddRef(); | ||||
user.Presence = new SocketPresence(null, UserStatus.Online); | |||||
user.Presence = new SocketPresence(UserStatus.Online, null); | |||||
return user; | return user; | ||||
}); | }); | ||||
} | } | ||||
@@ -1311,7 +1311,7 @@ namespace Discord.WebSocket | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
before = new SocketPresence(null, UserStatus.Offline); | |||||
before = new SocketPresence(UserStatus.Offline, null); | |||||
user = guild.AddOrUpdateUser(data); | user = guild.AddOrUpdateUser(data); | ||||
} | } | ||||
@@ -3,6 +3,7 @@ using Discord.Rest; | |||||
using System; | using System; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using GameEntity = Discord.Game; | |||||
using Model = Discord.API.User; | using Model = Discord.API.User; | ||||
namespace Discord.WebSocket | namespace Discord.WebSocket | ||||
@@ -10,6 +11,8 @@ namespace Discord.WebSocket | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class SocketSelfUser : SocketUser, ISelfUser | public class SocketSelfUser : SocketUser, ISelfUser | ||||
{ | { | ||||
private DateTimeOffset? _statusSince; | |||||
public string Email { get; private set; } | public string Email { get; private set; } | ||||
public bool IsVerified { get; private set; } | public bool IsVerified { get; private set; } | ||||
public bool IsMfaEnabled { get; private set; } | public bool IsMfaEnabled { get; private set; } | ||||
@@ -44,12 +47,57 @@ namespace Discord.WebSocket | |||||
IsMfaEnabled = model.MfaEnabled.Value; | IsMfaEnabled = model.MfaEnabled.Value; | ||||
} | } | ||||
public Task ModifyAsync(Action<ModifyCurrentUserParams> func) | |||||
=> UserHelper.ModifyAsync(this, Discord, func); | |||||
public Task ModifyAsync(Action<ModifyCurrentUserParams> func, RequestOptions options = null) | |||||
=> UserHelper.ModifyAsync(this, Discord, func, options); | |||||
public async Task ModifyStatusAsync(Action<ModifyPresenceParams> func, RequestOptions options = null) | |||||
{ | |||||
var args = new ModifyPresenceParams(); | |||||
func(args); | |||||
internal new SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser; | |||||
UserStatus status; | |||||
if (args.Status.IsSpecified) | |||||
{ | |||||
status = args.Status.Value; | |||||
if (status == UserStatus.AFK) | |||||
_statusSince = DateTimeOffset.UtcNow; | |||||
else | |||||
_statusSince = null; | |||||
} | |||||
else | |||||
status = Status; | |||||
//ISelfUser | |||||
Task ISelfUser.ModifyStatusAsync(Action<ModifyPresenceParams> func) { throw new NotSupportedException(); } | |||||
GameEntity? game; | |||||
if (args.Game.IsSpecified) | |||||
{ | |||||
var model = args.Game.Value; | |||||
if (model != null) | |||||
game = GameEntity.Create(model); | |||||
else | |||||
game = null; | |||||
} | |||||
else | |||||
game = Game; | |||||
Presence = new SocketPresence(status, game); | |||||
await SendStatus(status, game); | |||||
} | |||||
internal async Task SendStatus(UserStatus status, GameEntity? game) | |||||
{ | |||||
var gameModel = game != null ? new API.Game | |||||
{ | |||||
Name = game.Value.Name, | |||||
StreamType = game.Value.StreamType, | |||||
StreamUrl = game.Value.StreamUrl | |||||
} : null; | |||||
await Discord.ApiClient.SendStatusUpdateAsync( | |||||
status, | |||||
status == UserStatus.AFK, | |||||
_statusSince != null ? _statusSince.Value.ToUnixTimeMilliseconds() : (long?)null, | |||||
gameModel); | |||||
} | |||||
internal new SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser; | |||||
} | } | ||||
} | } |
@@ -12,7 +12,7 @@ namespace Discord.WebSocket | |||||
public override string Username { get; internal set; } | public override string Username { get; internal set; } | ||||
public override ushort DiscriminatorValue { get; internal set; } | public override ushort DiscriminatorValue { get; internal set; } | ||||
public override string AvatarId { get; internal set; } | public override string AvatarId { get; internal set; } | ||||
internal override SocketPresence Presence { get { return new SocketPresence(null, UserStatus.Offline); } set { } } | |||||
internal override SocketPresence Presence { get { return new SocketPresence(UserStatus.Offline, null); } set { } } | |||||
internal override SocketGlobalUser GlobalUser { get { throw new NotSupportedException(); } } | internal override SocketGlobalUser GlobalUser { get { throw new NotSupportedException(); } } | ||||