diff --git a/Iceshrimp.Frontend/Components/Compose.razor b/Iceshrimp.Frontend/Components/Compose.razor index 8be5430f..bc8a7690 100644 --- a/Iceshrimp.Frontend/Components/Compose.razor +++ b/Iceshrimp.Frontend/Components/Compose.razor @@ -63,6 +63,9 @@
Upload!
+ @@ -113,6 +116,61 @@ } } + @if (NoteDraft.Poll != null) + { +
+
+ @foreach (var entry in PollChoices) + { +
+ + +
+ } + @if (PollChoices.Count < 10) + { +
+ + +
+ } +
+ + +
+
+ + +
+ @switch (PollExpires) + { + case PollExpire.Never: + break; + case PollExpire.ExpiresAt: + + break; + case PollExpire.ExpiresAfter: + + + break; + default: + throw new ArgumentOutOfRangeException(); + } +
+
+ } @if (Preview) {
@@ -147,6 +205,12 @@ private bool SendLock { get; set; } = false; private int UploadingFiles { get; set; } private string? AttachedQuote { get; set; } + private List PollChoices { get; set; } = []; + private string PollEntry { get; set; } = ""; + private PollExpire PollExpires { get; set; } + private DateTime PollExpireTime { get; set; } + private int PollExpireLen { get; set; } + private PollExpireAfter PollExpiresAft { get; set; } private NoteCreateRequest NoteDraft { get; set; } = new() { @@ -157,6 +221,25 @@ private Dictionary AvailablePlaceholders { get; set; } = new() { { "default", "What's on your mind?" }, { "reply", "Reply goes here!" }, { "quote", "Quote this post!" } }; + private class Choice + { + public required string Value { get; set; } + } + + private enum PollExpire + { + Never, + ExpiresAt, + ExpiresAfter + } + + private enum PollExpireAfter + { + Minutes, + Hours, + Days, + } + private bool SendingDisabled() => NoteLength - ((NoteDraft.Cw?.Length ?? 0) + NoteDraft.Text.Length) < 0 || UploadingFiles != 0; @@ -317,6 +400,24 @@ } NoteDraft.RenoteId ??= AttachedQuote; + + if (NoteDraft.Poll != null) + { + NoteDraft.Poll.Choices = PollChoices.Select(p => p.Value).ToList(); + NoteDraft.Poll.ExpiresAt = PollExpires switch + { + PollExpire.ExpiresAt => PollExpireTime.ToUniversalTime(), + PollExpire.ExpiresAfter => PollExpiresAft switch + { + PollExpireAfter.Minutes => DateTime.UtcNow.AddMinutes(Math.Min(PollExpireLen, 5)), + PollExpireAfter.Hours => DateTime.UtcNow.AddHours(Math.Min(PollExpireLen, 1)), + PollExpireAfter.Days => DateTime.UtcNow.AddDays(Math.Min(PollExpireLen, 1)), + _ => throw new ArgumentOutOfRangeException() + }, + _ => null + }; + } + try { await ApiService.Notes.CreateNoteAsync(NoteDraft); @@ -339,6 +440,29 @@ SendButton.State = StateButton.StateEnum.Initial; // FIXME: Implement timeline refresh and call it here. } + + private void TogglePoll() + { + if (NoteDraft.Poll != null) + { + NoteDraft.Poll = null; + } + else + { + NoteDraft.Poll = new PollRequest + { + ExpiresAt = null, + Multiple = false, + Choices = [] + }; + PollChoices = []; + PollEntry = ""; + PollExpires = PollExpire.Never; + PollExpireTime = DateTime.Now; + PollExpireLen = 7; + PollExpiresAft = PollExpireAfter.Days; + } + } private void ToggleCw() { @@ -361,6 +485,17 @@ StateHasChanged(); } + private void AddPollChoice() + { + PollChoices.Add(new Choice { Value = PollEntry }); + PollEntry = ""; + } + + private void DeletePollChoice(Choice choice) + { + PollChoices.Remove(choice); + } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) diff --git a/Iceshrimp.Frontend/Components/Compose.razor.css b/Iceshrimp.Frontend/Components/Compose.razor.css index ccdbf5c6..d90c5ec4 100644 --- a/Iceshrimp.Frontend/Components/Compose.razor.css +++ b/Iceshrimp.Frontend/Components/Compose.razor.css @@ -19,6 +19,35 @@ resize: vertical; } +.poll .choice { + display: flex; + flex-direction: row; + align-items: center; + + .input { + width: 100%; + } +} + +.poll .expire { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 0.5em; + align-items: end; + margin-top: 0.5em; + + select { + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + } +} + +input[type="checkbox"] { + display: inline-block; +} + .compose .attachments { display: flex; flex-wrap: wrap;