/// <summary> /// Generates a new task panel /// </summary> /// <param name="cl">Class to generate it for</param> /// <param name="parent">ListView associated with the class</param> /// <param name="task">Task to add</param> /// <returns>A new ListViewItem for the task</returns> public static ListViewItem GenerateTaskPanel(Class cl, ListView parent, Task task) { #region Containers // Create the content area Grid content = new Grid { Margin = new Thickness(0), Height = 75, Background = MainPage.LightGrayBrush, Tag = "Task" }; // Create the list of content items and a delegate to add them to the list List<UIElement> contentItems = new List<UIElement>(); Action<UIElement> registerItem = i => { contentItems.Add(i); }; // The main ListViewItem ListViewItem panel = new ListViewItem { Background = MainPage.TransparentBrush, Margin = new Thickness(0, 0, 0, 5), Height = 75, Tag = false, // Is Panel Expanded HorizontalContentAlignment = HorizontalAlignment.Stretch, VerticalContentAlignment = VerticalAlignment.Top, Padding = new Thickness(0), BorderBrush = MainPage.MediumGrayBrush, BorderThickness = new Thickness(1), }; #endregion #region Title // Task title TextBlock title = new TextBlock { Text = task.Title.Trim(), TextAlignment = TextAlignment.Left, FontSize = 25, Foreground = MainPage.BlueBrush, Margin = new Thickness(5, 0, 0, 0) }; // Sizing title.Measure(new Size(0, 0)); title.Arrange(new Rect(0, 0, 0, 0)); registerItem(title); #endregion #region Finish Button // The check mark that marks the task as completed Button finish = new Button { FontFamily = Icons.IconFont, Content = task.Complete == 1 ? Icons.Cancel : Icons.Accept, Margin = new Thickness(title.ActualWidth + 5, 5, 0, 0), HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Background = MainPage.TransparentBrush }; // Remove the task when the button is pressed finish.Tapped += (sender, args) => { TaskList.RemoveTask(cl, parent, panel, task); }; registerItem(finish); #endregion #region Info Box // Info box TextBox info = new TextBox { TextAlignment = TextAlignment.Left, Foreground = new SolidColorBrush(Color.FromArgb(255, 50, 50, 50)), HorizontalAlignment = HorizontalAlignment.Left, TextWrapping = TextWrapping.Wrap, BorderThickness = new Thickness(0), AcceptsReturn = true, Width = parent.Width / 3 + 25, Tag = false, // Edit mode IsReadOnly = true, // Edit mode property Background = MainPage.TransparentBrush, // Edit mode property IsHitTestVisible = false // Edit mode property }; // Add the text - only works if you append each character foreach (char c in task.Info) { info.Text += c.ToString(); } // Border around the info box Border infoBorder = new Border { Child = info, Background = MainPage.MediumGrayBrush, Margin = new Thickness(5, 36, 0, 7), HorizontalAlignment = HorizontalAlignment.Left, BorderThickness = new Thickness(0), Padding = new Thickness(0) }; registerItem(infoBorder); // Edit button for the info box Button edit = new Button { FontFamily = Icons.IconFont, Content = Icons.Edit, Width = 20, Height = 20, FontSize = 10, Padding = new Thickness(0), Background = MainPage.TransparentBrush, VerticalAlignment = VerticalAlignment.Bottom, HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(parent.Width / 3 + 10, 36, 0, 7) }; // Toggles edit mode for the info box edit.Click += (sender, args) => { if (!(bool) info.Tag) { info.Tag = true; edit.Content = Icons.Save; info.IsReadOnly = false; info.Background = new SolidColorBrush(Colors.White); info.IsHitTestVisible = true; info.Focus(FocusState.Pointer); info.SelectionStart = info.Text.Length; info.SelectionLength = 0; } else { info.Tag = false; edit.Content = Icons.Edit; info.IsReadOnly = true; info.Background = MainPage.MediumGrayBrush; info.IsHitTestVisible = false; DataHandler.EditTask(task.Id, "Info", info.Text); } }; registerItem(edit); #endregion #region Circular Progress Bar // Progress bar background (gray) CircularProgressBar progressBack = new CircularProgressBar { Percentage = 100, SegmentColor = MainPage.MediumGrayBrush, Radius = 30, StrokeThickness = 5, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(0, 2.75, 2.75 + 30, 0) }; registerItem(progressBack); // Progress bar foreground (blue) CircularProgressBar progressFront = new CircularProgressBar { Percentage = 0, SegmentColor = MainPage.BlueBrush, Radius = 30, StrokeThickness = 5, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(0, 2.75, 2.75 + 30, 0), Transitions = new TransitionCollection() }; registerItem(progressFront); // Text inside the progress bar that shows the time remaining TextBlock timeLeft = new TextBlock { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, Text = string.Empty, FontSize = 12, Foreground = MainPage.BlueBrush, TextAlignment = TextAlignment.Center }; // Helps with alignment for the progress bar Border border = new Border { BorderBrush = MainPage.BlueBrush, BorderThickness = new Thickness(0), Child = timeLeft, Height = 70, Width = 70, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, Margin = progressFront.Margin }; registerItem(border); // Delegate for Action updateProgress = () => { // Clamp the progress to 100% progressFront.Percentage = Math.Min(Util.GetPercentTime(task) * 100, 100); // Finished tasks get an orange color bool finished = false; if (progressFront.Percentage.Equals(100.0)) { finished = true; progressFront.SegmentColor = MainPage.OrangeRedBrush; timeLeft.Foreground = MainPage.OrangeRedBrush; } // Set the new text timeLeft.Text = $"{Util.GetTimeString(task)}{(finished ? " ago" : string.Empty)}"; }; updateProgress(); // Update the progress every second ThreadPoolTimer.CreatePeriodicTimer( async poolTimer => { await progressFront.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { updateProgress(); }); }, new TimeSpan(0, 0, 0, 1)); #endregion #region Assigned/Due Times // Assigned/due info RichTextBlock timeInfo = new RichTextBlock { FontSize = 14, Margin = new Thickness(-5), TextAlignment = TextAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch, TextWrapping = TextWrapping.NoWrap }; // "Assigned on" and "Due on" text // Separated with different colors Run assignedText = new Run { Text = "Assigned: ", Foreground = MainPage.BlueBrush }; Run assignedDate = new Run { Text = $"{task.AssignedOn}", Foreground = MainPage.GreenBrush }; Run dueText = new Run { Text = "Due: ", Foreground = MainPage.BlueBrush }; Run dueDate = new Run { Text = $"{task.DueOn}", Foreground = MainPage.OrangeRedBrush }; // Set up lines Paragraph p1 = new Paragraph(); p1.Inlines.Add(assignedText); p1.Inlines.Add(assignedDate); Paragraph p2 = new Paragraph(); p2.Inlines.Add(dueText); p2.Inlines.Add(dueDate); // Add the info to the text box timeInfo.Blocks.Add(p1); timeInfo.Blocks.Add(p2); // Container for time info Border timeInfoBorder = new Border { Child = timeInfo, BorderBrush = MainPage.BlueBrush, BorderThickness = new Thickness(0), Margin = new Thickness(parent.Width / 3 + 35, 36, 105, 5), Padding = new Thickness(0), VerticalAlignment = VerticalAlignment.Stretch }; registerItem(timeInfoBorder); #endregion #region Expand Button // Button that expands the box Button expand = new Button { HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, Height = 73, Width = 25, Margin = new Thickness(0, 0, 0, 0), Content = Icons.Down, FontFamily = Icons.IconFont, Padding = new Thickness(0) }; // This makes sure all other task panels collapse smoothly if a new one is opened expand.Tapped += (sender, args) => { // Get the new height based on the tag that tells you if the panel is open or closed int to = !(bool) panel.Tag ? 412 : 75; // Set the new button content to the opposite arrow expand.Content = !(bool) panel.Tag ? Icons.Up : Icons.Down; // If the panel is not opened if (!(bool) panel.Tag) { // For each task that is open and has content foreach (ListViewItem item in parent.Items.Cast<ListViewItem>() .Where(item => (bool?) item.Tag ?? false && item.Content != null)) { // If the grid content is not null and the grid tag is not null if (!((item.Content as Grid)?.Tag as bool? ?? false)) { // Find the button in the grid that has the Up icon foreach (Button btn in (item.Content as Grid).Children.OfType<Button>() .Where(btn => (string) btn.Content == Icons.Up)) { // ... And change it to the down icon btn.Content = Icons.Down; } // Collapse the panel Util.CreateAnimation(150, item, null, 75, "Height").Begin(); // Set the tag to false indicating the panel is closed item.Tag = false; } } } // Once all other panels have been collapsed, expand the new one Util.CreateAnimation(150, panel, null, to, "Height").Begin(); // Set its tag appropriately panel.Tag = !(bool) panel.Tag; }; registerItem(expand); #endregion #region Calendar // Calendar showing date assigned, date due, today CalendarView calendar = new CalendarView { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Top, SelectionMode = CalendarViewSelectionMode.None, BlackoutForeground = new SolidColorBrush(Colors.White), Background = MainPage.MediumGrayBrush, CalendarItemBackground = MainPage.TransparentBrush, BorderBrush = MainPage.TransparentBrush, CalendarItemBorderBrush = MainPage.TransparentBrush, OutOfScopeBackground = MainPage.TransparentBrush, OutOfScopeForeground = new SolidColorBrush(Colors.Gray), Margin = new Thickness(parent.Width / 3 + 35, 75, 3, 5), }; // Override item rendering to change colors calendar.CalendarViewDayItemChanging += (sender, args) => { if (args.Item == null) { return; } DateTime day = args.Item.Date.DateTime; if (day.Date == DateTime.Parse(task.AssignedOn.ToString()).Date) { args.Item.Background = MainPage.GreenBrush; args.Item.IsBlackout = true; // Hack to change the foreground color } else if (day.Date == DateTime.Parse(task.DueOn.ToString()).Date) { args.Item.Background = MainPage.OrangeRedBrush; args.Item.IsBlackout = true; } if (day.Date == DateTime.Today) { args.Item.IsBlackout = false; } }; calendar.SetDisplayDate(DateTime.Today); registerItem(calendar); #endregion #region Sizing and Creation // Sizing parent.SizeChanged += (sender, args) => { info.Width = args.NewSize.Width / 3 + 25; edit.Margin = new Thickness(args.NewSize.Width / 3 + 10, 36, 0, 7); calendar.Margin = new Thickness(args.NewSize.Width / 3 + 35, 75, 3, 5); timeInfoBorder.Margin = new Thickness(args.NewSize.Width / 3 + 35, 36, 105, 5); }; panel.SizeChanged += (sender, args) => { content.Height = args.NewSize.Height; }; // Add each element in the contentItems list foreach (UIElement element in contentItems) { content.Children.Add(element); } // Set the container content panel.Content = content; return panel; #endregion }
private double BlockHeightOf( TextBlock t ) { t.Measure( new Size( double.PositiveInfinity, double.PositiveInfinity ) ); t.Arrange( new Rect( new Point(), t.DesiredSize ) ); /* INTENSIVE_LOG if( t.FontSize == 16 ) { Logger.Log( ID, string.Format( "FontSize 16 detected {0}, Should be {1}. Text {2}", t.FontSize, FontSize, t.Text ), LogType.DEBUG ); } //*/ return t.ActualHeight; }