| @@ -420,12 +420,23 @@ namespace Discord | |||||
| else | else | ||||
| msg = _messages[x.Id] ?? new Message(this, x.Id, x.ChannelId, x.Author.Id); | msg = _messages[x.Id] ?? new Message(this, x.Id, x.ChannelId, x.Author.Id); | ||||
| if (msg != null) | if (msg != null) | ||||
| msg.Update(x); | |||||
| if (_config.TrackActivity) | |||||
| { | { | ||||
| var user = _users[x.Author.Id]; | |||||
| if (user != null) | |||||
| user.UpdateActivity(x.Timestamp); | |||||
| msg.Update(x); | |||||
| if (_config.TrackActivity) | |||||
| { | |||||
| if (channel.IsPrivate) | |||||
| { | |||||
| var user = msg.User; | |||||
| if (user != null) | |||||
| user.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp); | |||||
| } | |||||
| else | |||||
| { | |||||
| var member = msg.Member; | |||||
| if (member != null) | |||||
| member.UpdateActivity(msg.EditedTimestamp ?? msg.Timestamp); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| return msg; | return msg; | ||||
| }) | }) | ||||
| @@ -118,18 +118,14 @@ namespace Discord | |||||
| { | { | ||||
| if (_voiceSocket.CurrentVoiceServerId != null) | if (_voiceSocket.CurrentVoiceServerId != null) | ||||
| { | { | ||||
| if (_config.TrackActivity) | |||||
| { | |||||
| var user = _users[e.UserId]; | |||||
| if (user != null) | |||||
| user.UpdateActivity(); | |||||
| } | |||||
| var member = _members[e.UserId, _voiceSocket.CurrentVoiceServerId]; | var member = _members[e.UserId, _voiceSocket.CurrentVoiceServerId]; | ||||
| bool value = e.IsSpeaking; | bool value = e.IsSpeaking; | ||||
| if (member.IsSpeaking != value) | if (member.IsSpeaking != value) | ||||
| { | { | ||||
| member.IsSpeaking = value; | member.IsSpeaking = value; | ||||
| RaiseUserIsSpeaking(member, value); | RaiseUserIsSpeaking(member, value); | ||||
| if (_config.TrackActivity) | |||||
| member.UpdateActivity(); | |||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -359,10 +355,10 @@ namespace Discord | |||||
| var data = e.Payload.ToObject<Events.GuildMemberAdd>(_serializer); | var data = e.Payload.ToObject<Events.GuildMemberAdd>(_serializer); | ||||
| var user = _users.GetOrAdd(data.User.Id); | var user = _users.GetOrAdd(data.User.Id); | ||||
| user.Update(data.User); | user.Update(data.User); | ||||
| if (_config.TrackActivity) | |||||
| user.UpdateActivity(); | |||||
| var member = _members.GetOrAdd(data.User.Id, data.GuildId); | var member = _members.GetOrAdd(data.User.Id, data.GuildId); | ||||
| member.Update(data); | member.Update(data); | ||||
| if (_config.TrackActivity) | |||||
| member.UpdateActivity(); | |||||
| RaiseUserAdded(member); | RaiseUserAdded(member); | ||||
| } | } | ||||
| break; | break; | ||||
| @@ -455,7 +451,21 @@ namespace Discord | |||||
| msg = _messages.GetOrAdd(data.Id, data.ChannelId, data.Author.Id); | msg = _messages.GetOrAdd(data.Id, data.ChannelId, data.Author.Id); | ||||
| msg.Update(data); | msg.Update(data); | ||||
| if (_config.TrackActivity) | if (_config.TrackActivity) | ||||
| msg.User.UpdateActivity(data.Timestamp); | |||||
| { | |||||
| var channel = msg.Channel; | |||||
| if (channel == null || channel.IsPrivate) | |||||
| { | |||||
| var user = msg.User; | |||||
| if (user != null) | |||||
| user.UpdateActivity(data.Timestamp); | |||||
| } | |||||
| else | |||||
| { | |||||
| var member = msg.Member; | |||||
| if (member != null) | |||||
| member.UpdateActivity(data.Timestamp); | |||||
| } | |||||
| } | |||||
| if (wasLocal) | if (wasLocal) | ||||
| RaiseMessageSent(msg); | RaiseMessageSent(msg); | ||||
| RaiseMessageCreated(msg); | RaiseMessageCreated(msg); | ||||
| @@ -537,11 +547,23 @@ namespace Discord | |||||
| if (user != null) | if (user != null) | ||||
| { | { | ||||
| if (_config.TrackActivity) | |||||
| user.UpdateActivity(); | |||||
| if (channel != null) | if (channel != null) | ||||
| RaiseUserIsTyping(user, channel); | RaiseUserIsTyping(user, channel); | ||||
| } | } | ||||
| if (_config.TrackActivity) | |||||
| { | |||||
| if (channel.IsPrivate) | |||||
| { | |||||
| if (user != null) | |||||
| user.UpdateActivity(); | |||||
| } | |||||
| else | |||||
| { | |||||
| var member = _members[data.UserId, channel.ServerId]; | |||||
| if (member != null) | |||||
| member.UpdateActivity(); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| break; | break; | ||||
| @@ -41,7 +41,7 @@ namespace Discord | |||||
| private bool _useMessageQueue = false; | private bool _useMessageQueue = false; | ||||
| /// <summary> (Experimental) Maintains the LastActivity property for users, showing when they last made an action (sent message, joined server, typed, etc). </summary> | /// <summary> (Experimental) Maintains the LastActivity property for users, showing when they last made an action (sent message, joined server, typed, etc). </summary> | ||||
| public bool TrackActivity { get { return _trackActivity; } set { SetValue(ref _trackActivity, value); } } | public bool TrackActivity { get { return _trackActivity; } set { SetValue(ref _trackActivity, value); } } | ||||
| private bool _trackActivity = false; | |||||
| private bool _trackActivity = true; | |||||
| //Lock | //Lock | ||||
| private bool _isLocked; | private bool _isLocked; | ||||
| @@ -20,11 +20,18 @@ namespace Discord | |||||
| public string SessionId { get; internal set; } | public string SessionId { get; internal set; } | ||||
| public string Token { get; internal set; } | public string Token { get; internal set; } | ||||
| /// <summary> Returns the id for the game this user is currently playing. </summary> | /// <summary> Returns the id for the game this user is currently playing. </summary> | ||||
| public string GameId { get; internal set; } | public string GameId { get; internal set; } | ||||
| /// <summary> Returns the current status for this user. </summary> | /// <summary> Returns the current status for this user. </summary> | ||||
| public string Status { get; internal set; } | public string Status { get; internal set; } | ||||
| /// <summary> Returns the time this user's status was last changed in this server. </summary> | |||||
| public DateTime StatusSince { get; internal set; } | public DateTime StatusSince { get; internal set; } | ||||
| /// <summary> Returns the time this user last sent/edited a message, started typing or sent voice data in this server. </summary> | |||||
| public DateTime? LastActivity { get; private set; } | |||||
| /// <summary> Returns the time this user was last seen online in this server. </summary> | |||||
| public DateTime? LastOnline => Status != UserStatus.Offline ? DateTime.UtcNow : _lastOnline; | |||||
| private DateTime _lastOnline; | |||||
| public string UserId { get; } | public string UserId { get; } | ||||
| [JsonIgnore] | [JsonIgnore] | ||||
| @@ -50,7 +57,8 @@ namespace Discord | |||||
| _client = client; | _client = client; | ||||
| UserId = userId; | UserId = userId; | ||||
| ServerId = serverId; | ServerId = serverId; | ||||
| } | |||||
| Status = UserStatus.Offline; | |||||
| } | |||||
| public override string ToString() => UserId; | public override string ToString() => UserId; | ||||
| @@ -70,8 +78,11 @@ namespace Discord | |||||
| { | { | ||||
| if (Status != model.Status) | if (Status != model.Status) | ||||
| { | { | ||||
| Status = model.Status; | |||||
| StatusSince = DateTime.UtcNow; | |||||
| var now = DateTime.UtcNow; | |||||
| Status = model.Status; | |||||
| StatusSince = now; | |||||
| if (Status == UserStatus.Offline) | |||||
| _lastOnline = now; | |||||
| } | } | ||||
| GameId = model.GameId; | GameId = model.GameId; | ||||
| } | } | ||||
| @@ -90,5 +101,11 @@ namespace Discord | |||||
| if (model.IsSuppressed.HasValue) | if (model.IsSuppressed.HasValue) | ||||
| IsSuppressed = model.IsSuppressed.Value; | IsSuppressed = model.IsSuppressed.Value; | ||||
| } | } | ||||
| } | |||||
| internal void UpdateActivity(DateTime? activity = null) | |||||
| { | |||||
| if (LastActivity == null || activity > LastActivity.Value) | |||||
| LastActivity = activity ?? DateTime.UtcNow; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -11,6 +11,7 @@ namespace Discord | |||||
| { | { | ||||
| private readonly DiscordClient _client; | private readonly DiscordClient _client; | ||||
| private int _refs; | private int _refs; | ||||
| private DateTime? _lastPrivateActivity; | |||||
| /// <summary> Returns the unique identifier for this user. </summary> | /// <summary> Returns the unique identifier for this user. </summary> | ||||
| public string Id { get; } | public string Id { get; } | ||||
| @@ -44,9 +45,27 @@ namespace Discord | |||||
| public IEnumerable<Server> Servers => _client.Servers.Where(x => x.HasMember(Id)); | public IEnumerable<Server> Servers => _client.Servers.Where(x => x.HasMember(Id)); | ||||
| /// <summary> Returns a collection of all messages this user has sent that are still in cache. </summary> | /// <summary> Returns a collection of all messages this user has sent that are still in cache. </summary> | ||||
| public IEnumerable<Message> Messages => _client.Messages.Where(x => x.UserId == Id); | public IEnumerable<Message> Messages => _client.Messages.Where(x => x.UserId == Id); | ||||
| /// <summary> Returns the time this user last sent a message. </summary> | |||||
| public DateTime? LastActivity { get; private set; } | |||||
| /// <summary> Returns the id for the game this user is currently playing. </summary> | |||||
| public string GameId => Memberships.Where(x => x.GameId != null).Select(x => x.GameId).FirstOrDefault(); | |||||
| /// <summary> Returns the current status for this user. </summary> | |||||
| public string Status => Memberships.OrderByDescending(x => x.StatusSince).Select(x => x.Status).FirstOrDefault(); | |||||
| /// <summary> Returns the time this user's status was last changed. </summary> | |||||
| public DateTime StatusSince => Memberships.OrderByDescending(x => x.StatusSince).Select(x => x.StatusSince).First(); | |||||
| /// <summary> Returns the time this user last sent/edited a message, started typing or sent voice data. </summary> | |||||
| public DateTime? LastActivity | |||||
| { | |||||
| get | |||||
| { | |||||
| var lastServerActivity = Memberships.OrderByDescending(x => x.LastActivity).Select(x => x.LastActivity).FirstOrDefault(); | |||||
| if (lastServerActivity == null || (_lastPrivateActivity != null && _lastPrivateActivity.Value > lastServerActivity.Value)) | |||||
| return _lastPrivateActivity; | |||||
| else | |||||
| return lastServerActivity; | |||||
| } | |||||
| } | |||||
| /// <summary> Returns the time this user was last seen online. </summary> | |||||
| public DateTime? LastOnline => Memberships.OrderByDescending(x => x.LastOnline).Select(x => x.LastOnline).FirstOrDefault(); | |||||
| internal User(DiscordClient client, string id) | internal User(DiscordClient client, string id) | ||||
| { | { | ||||
| @@ -66,11 +85,10 @@ namespace Discord | |||||
| Email = model.Email; | Email = model.Email; | ||||
| IsVerified = model.IsVerified; | IsVerified = model.IsVerified; | ||||
| } | } | ||||
| internal void UpdateActivity(DateTime? activity = null) | internal void UpdateActivity(DateTime? activity = null) | ||||
| { | { | ||||
| if (LastActivity == null || activity > LastActivity.Value) | |||||
| LastActivity = activity ?? DateTime.UtcNow; | |||||
| if (_lastPrivateActivity == null || activity > _lastPrivateActivity.Value) | |||||
| _lastPrivateActivity = activity ?? DateTime.UtcNow; | |||||
| } | } | ||||
| public override string ToString() => Name; | public override string ToString() => Name; | ||||