private static async Task AddGroupConversationThread(GraphServiceClient graphClient) { var posts = new ConversationThreadPostsCollectionPage(); posts.Add(new Post { Body = new ItemBody { Content = "Welcome to this group!", ContentType = BodyType.Text, } }); var ct = new ConversationThread { Topic = "The Microsoft Graph SDK!", Posts = posts }; var unifiedGroups = await graphClient.Groups .Request() .Filter("groupTypes/any(grp: grp eq 'Unified')") .GetAsync(); var groupEvents = await graphClient .Groups[unifiedGroups.FirstOrDefault().Id].Threads .Request() .AddAsync(ct); }
// The time and star secton on the right side. private async void ConversationInfoHeader_Tap(object sender, System.Windows.Input.GestureEventArgs e) { FrameworkElement grid = (FrameworkElement)sender; ConversationThread conversation = (ConversationThread)grid.DataContext; ProgressIndicator.IsIndeterminate = true; try { if (conversation != null) { Account account = App.AccountManager.GetCurrentAccount(); if (account != null) { if (conversation.HasStar) { // Remove the star from any starred messages await account.SetStarAsync(conversation.Messages, starred : false); } else { // Add a star to the latest message await account.SetStarAsync(conversation.Messages.First(), starred : true); } // Refresh the UI grid.DataContext = null; grid.DataContext = conversation; } } } finally { ProgressIndicator.IsIndeterminate = false; } }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { ConversationThread conversation = (ConversationThread)value; // TODO: Super Stars - No IMAP support - Search term “has:blue-star”? http://googlesystem.blogspot.com/2008/07/gmail-superstars.html return((conversation.HasStar) ? Yellow : null); }
public virtual async Task SelectConversationAsync(ConversationThread conversation) { ActiveConversation = conversation; await SetReadStatusAsync(conversation.Messages, true); // Sync full conversation body, from disk or network. foreach (MailMessage message in conversation.Messages) { ObjectWHeaders view = message.GetHtmlView(); await LazyLoadBodyPartAsync(message, view); } }
protected override void OnNavigatedTo(NavigationEventArgs e) { Account account = App.AccountManager.GetCurrentAccount(); if (account != null) { Conversation = account.ActiveConversation; GetLabelsAsync(); } base.OnNavigatedTo(e); }
private async void ConversationHeader_Tap(object sender, System.Windows.Input.GestureEventArgs e) { FrameworkElement grid = (FrameworkElement)sender; ConversationThread conversation = (ConversationThread)grid.DataContext; if (conversation != null) { Account account = App.AccountManager.GetCurrentAccount(); if (account != null) { await account.SelectConversationAsync(conversation); NavigationService.Navigate(new Uri("/ConversationPage.xaml", UriKind.Relative)); } } }
protected override void OnNavigatedTo(NavigationEventArgs e) { Account account = App.AccountManager.GetCurrentAccount(); if (account != null) { Conversation = account.ActiveConversation; if (Conversation == null) { // This happens after opening an attachment and then hitting back. // TODO: Why do we lose app state after opening an attachment? NavigationService.GoBack(); } DataContext = null; // Force refresh after editing labels DataContext = Conversation; } base.OnNavigatedTo(e); }
/// <summary> /// Update the navigation property threads in groups /// <param name="body"></param> /// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param> /// </summary> public RequestInformation CreatePatchRequestInformation(ConversationThread body, Action <ConversationThreadItemRequestBuilderPatchRequestConfiguration> requestConfiguration = default) { _ = body ?? throw new ArgumentNullException(nameof(body)); var requestInfo = new RequestInformation { HttpMethod = Method.PATCH, UrlTemplate = UrlTemplate, PathParameters = PathParameters, }; requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); if (requestConfiguration != null) { var requestConfig = new ConversationThreadItemRequestBuilderPatchRequestConfiguration(); requestConfiguration.Invoke(requestConfig); requestInfo.AddRequestOptions(requestConfig.Options); requestInfo.AddHeaders(requestConfig.Headers); } return(requestInfo); }
static void AddConsumers(ConversationThread conversation, ChartTable chart, OutputTimelineOptions options) { foreach (var consumer in conversation.Consumers.OrderBy(x => x.Message.StartTime)) { var sb = new StringBuilder(60); if (conversation.Depth > 1) { sb.Append(' ', (conversation.Depth - 1) * 2); } if (conversation.Depth > 0) { sb.Append("\x2514 "); } sb.Append("Consume "); sb.Append(options.MessageType(consumer.Message)); chart.Add(sb.ToString(), consumer.Message.StartTime, consumer.Message.ElapsedTime, consumer.Message.Address); } }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Attachment attachment = (Attachment)value; Account account = App.AccountManager.GetCurrentAccount(); ConversationThread thread = account.ActiveConversation; // Gind the message by matching the file name // TODO: This could be wrong because the same conversation thread may have // multiple messages with the same attachment name. MailMessage message = thread.Messages.Where( msg => msg.Attachments.FirstOrDefault( att => att.Filename == attachment.Filename) != null).First(); // TODO: Size if (attachment.Scope == Scope.HeadersAndBody || account.MailStorage.HasMessagePart(message.GetThreadId(), message.GetMessageId(), attachment.BodyId)) { return(attachment.Filename + " (open)"); } else { return(attachment.Filename + " (download)"); } }
protected override async void OnNavigatedTo(NavigationEventArgs e) { // The query parameter is used to tell us if we're in a reply mode. string[] parts = e.Uri.ToString().Split('?'); if (parts.Length > 1 && !string.IsNullOrEmpty(parts[1])) { string query = parts[1]; Account account = App.AccountManager.GetCurrentAccount(); ConversationThread mailThread = account.ActiveConversation; MailMessage lastMessage = mailThread.Messages.First(); // They're in reverse order. if (query.Equals("Forward")) { // No addresses // TODO: Prefix subject SubjectField.Text = lastMessage.Subject; } else if (query.Equals("ReplyAll")) { // Include all addresses if (lastMessage.ReplyTo.Count > 0) { ToField.Text = string.Join(", ", lastMessage.ReplyTo); } else { ToField.Text = string.Join(", ", new[] { lastMessage.From }.Concat( lastMessage.To.Where(mailAddress => // Filter yourself out of the to line, unless you explicitly sent the e-mail. !mailAddress.Address.Equals(account.Info.Address, StringComparison.OrdinalIgnoreCase) ))); } // TODO: CC // TODO: Prefix subject SubjectField.Text = lastMessage.Subject; // For threading _additionalHeaders.Add(new KeyValuePair <string, string>("In-Reply-To", lastMessage.MessageID)); _additionalHeaders.Add(new KeyValuePair <string, string>("References", lastMessage.MessageID)); } else if (query.Equals("Reply")) { // Include only the sender/reply-to if (lastMessage.ReplyTo.Count > 0) { ToField.Text = string.Join(", ", lastMessage.ReplyTo); } else { ToField.Text = lastMessage.From.ToString(); } // TODO: Prefix subject SubjectField.Text = lastMessage.Subject; // For threading _additionalHeaders.Add(new KeyValuePair <string, string>("In-Reply-To", lastMessage.MessageID)); _additionalHeaders.Add(new KeyValuePair <string, string>("References", lastMessage.MessageID)); } ObjectWHeaders view = lastMessage.GetTextView(); await account.LazyLoadBodyPartAsync(lastMessage, view); BodyField.Text = "\r\n\r\nOn " + lastMessage.Date.ToString("ddd, MMM d, yyyy a\\t h:mm tt") + ", " + lastMessage.From + " wrote:\r\n\r\n> " + view.Body.Replace("\r\n", "\r\n> "); } // TODO: Signature base.OnNavigatedTo(e); }
/// <summary> /// Output a timeline of messages published, sent, and consumed by the test harness. /// </summary> /// <param name="harness"></param> /// <param name="textWriter"></param> /// <param name="configure">Configure the timeout output options</param> /// <exception cref="ArgumentNullException"></exception> public static async Task OutputTimeline(this BusTestHarness harness, TextWriter textWriter, Action <OutputTimelineOptions> configure = default) { if (harness == null) { throw new ArgumentNullException(nameof(harness)); } if (textWriter == null) { throw new ArgumentNullException(nameof(textWriter)); } var options = new OutputTimelineOptions(); configure?.Invoke(options); options.Apply(harness); await harness.InactivityTask.ConfigureAwait(false); var produced = new List <Message>(); await foreach (var message in harness.Published.SelectAsync(_ => true).ConfigureAwait(false)) { produced.Add(new Message(message)); } await foreach (var message in harness.Sent.SelectAsync(_ => true).ConfigureAwait(false)) { produced.Add(new Message(message)); } var consumed = new List <Message>(); await foreach (var message in harness.Consumed.SelectAsync(_ => true).ConfigureAwait(false)) { consumed.Add(new Message(message)); } Dictionary <Guid?, ConversationThread> conversations = produced.GroupBy(m => m.ConversationId).Select(x => { List <Message> messages = x.OrderBy(m => m.StartTime).ToList(); var initiator = messages.FirstOrDefault(m => m.ParentMessageId == default) ?? messages.First(); var initiatorThread = new ConversationThread(initiator, 1); var stack = new Stack <ConversationThread>(); stack.Push(initiatorThread); while (stack.Any()) { var thread = stack.Pop(); List <Message> consumes = consumed.Where(message => message.MessageId == thread.Message.MessageId).ToList(); thread.Consumers.AddRange(consumes.Select(message => new ConversationConsumer(message))); IEnumerable <Message> threadMessages = x.Where(m => m.ParentMessageId == thread.Message.MessageId); foreach (var message in threadMessages) { var nextThread = new ConversationThread(message, thread.Depth + 1); thread.Nodes.Add(nextThread); stack.Push(nextThread); } } return(initiatorThread); }).ToDictionary(x => x.Message.ConversationId); var chart = new ChartTable(); foreach (var conversation in conversations.Values.OrderBy(x => x.Message.StartTime)) { var whitespace = new string(' ', (conversation.Depth - 1) * 2); var conversationLine = $"{whitespace}{conversation.Message.EventType} {options.MessageType(conversation.Message)}"; chart.Add(conversationLine, conversation.Message.StartTime, conversation.Message.ElapsedTime, conversation.Message.Address); AddConsumers(conversation, chart, options); var stack = new Stack <ConversationThread>(conversation.Nodes.OrderByDescending(x => x.Message.StartTime)); while (stack.Any()) { var current = stack.Pop(); whitespace = new string(' ', (current.Depth - 1) * 2); var line = $"{whitespace}{current.Message.EventType} {options.MessageType(current.Message)}"; chart.Add(line, current.Message.StartTime, current.Message.ElapsedTime, current.Message.Address); AddConsumers(current, chart, options); foreach (var node in current.Nodes.OrderByDescending(x => x.Message.StartTime)) { stack.Push(node); } } } options.GetTable(chart) .SetColumn(1, "Duration", typeof(int)) .SetRightNumberAlignment() .OutputTo(textWriter) .Write(); }