Compare commits

...

2 Commits

Author SHA1 Message Date
Anna 94ae2f65c6
feat: add has_next to response 2024-01-03 23:23:20 -05:00
Anna 4e29c174fe
feat: start adding pagination 2024-01-03 23:23:09 -05:00
4 changed files with 97 additions and 18 deletions

View File

@ -2,6 +2,7 @@ using System.Collections;
using System.Net.Http.Headers;
using Dalamud.Game.ClientState.Objects.Enums;
using EorzeaVotes.Model;
using EorzeaVotes.Utilities;
using Newtonsoft.Json;
namespace EorzeaVotes;
@ -10,8 +11,9 @@ internal class QuestionManager : IDisposable, IReadOnlyList<IQuestion> {
private Plugin Plugin { get; }
private HttpClient Http { get; }
private List<IQuestion> _questions = new();
private QuestionsResponse _questions = new();
private Guid _lastSeenActive = Guid.Empty;
private int _page = 1;
internal QuestionManager(Plugin plugin) {
this.Plugin = plugin;
@ -29,12 +31,34 @@ internal class QuestionManager : IDisposable, IReadOnlyList<IQuestion> {
this.Http.Dispose();
}
public int Count => this._questions.Count;
internal IQuestion? Current => this._questions.Current;
public IQuestion this[int index] => this._questions[index];
internal bool HasNext => this._questions.HasNext;
internal bool Loading { get; private set; }
internal int Page {
get => this._page;
set {
if (this.Loading) {
return;
}
this._page = Math.Max(1, value);
Task.Run(async () => {
this.Loading = true;
using var notLoading = new OnDispose(() => this.Loading = false);
await this.Check();
});
}
}
public int Count => this._questions.Page.Count;
public IQuestion this[int index] => this._questions.Page[index];
public IEnumerator<IQuestion> GetEnumerator() {
return this._questions.GetEnumerator();
return this._questions.Page.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
@ -102,12 +126,23 @@ internal class QuestionManager : IDisposable, IReadOnlyList<IQuestion> {
this.Plugin.SaveConfig();
}
[Serializable]
private class QuestionsResponse {
internal IQuestion? Current { get; init; }
internal List<IQuestion> Page { get; init; }
internal bool HasNext { get; init; }
}
internal async Task Check() {
await this.RegisterIfNecessary();
var req = this.MakeMessage(HttpMethod.Get, "/questions");
var req = this.MakeMessage(HttpMethod.Get, $"/questions?v=2&page={this._page}");
var resp = await this.Http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead);
var json = await resp.Content.ReadAsStringAsync();
this._questions = JsonConvert.DeserializeObject<List<IQuestion>>(json, Plugin.SerializerSettings) ?? new List<IQuestion>();
this._questions = JsonConvert.DeserializeObject<QuestionsResponse>(json, Plugin.SerializerSettings) ?? new QuestionsResponse {
Current = null,
Page = new(),
HasNext = false,
};
await this.OpenIfNew();
}

View File

@ -175,4 +175,16 @@ internal static class ImGuiHelper {
ImGui.SetNextItemWidth(-1);
return drawInput(label);
}
internal static bool IconButton(FontAwesomeIcon icon, string? id = null) {
ImGui.PushFont(UiBuilder.IconFont);
using var pop = new OnDispose(ImGui.PopFont);
var label = icon.ToIconString();
if (id != null) {
label += id;
}
return ImGui.Button(label);
}
}

View File

@ -1,4 +1,5 @@
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using EorzeaVotes.Model;
using EorzeaVotes.Utilities;
@ -21,14 +22,14 @@ internal class QuestionsTab {
using var endTabItem = new OnDispose(ImGui.EndTabItem);
if (this.Plugin.Manager.Count == 0) {
if (this.Plugin.Manager.Current == null && this.Plugin.Manager.Count == 0) {
ImGuiHelpers.CenteredText("Fetching questions - please wait...");
return;
}
ImGuiHelpers.CenteredText("Active question");
var active = this.Plugin.Manager.FirstOrDefault(q => q.Active);
var active = this.Plugin.Manager.Current;
if (active == null) {
ImGui.TextUnformatted("There is no active question at the moment.");
} else {
@ -89,16 +90,42 @@ internal class QuestionsTab {
ImGui.PushTextWrapPos();
using var pop = new OnDispose(ImGui.PopTextWrapPos);
foreach (var question in this.Plugin.Manager) {
if (question.Active || question is not FullQuestion full) {
continue;
}
ImGui.TextUnformatted(full.Text);
full.DrawResponses();
this.DrawMoreDetailsButton(full);
var loading = this.Plugin.Manager.Loading;
if (loading) {
ImGui.TextUnformatted("Loading...");
ImGui.Spacing();
} else {
foreach (var question in this.Plugin.Manager) {
if (question.Active || question is not FullQuestion full) {
continue;
}
ImGui.TextUnformatted(full.Text);
full.DrawResponses();
this.DrawMoreDetailsButton(full);
ImGui.Spacing();
}
}
// page buttons
using (ImGuiHelper.WithDisabled(loading || this.Plugin.Manager.Page == 1)) {
if (ImGuiHelper.IconButton(FontAwesomeIcon.ArrowLeft)) {
this.Plugin.Manager.Page -= 1;
}
}
ImGui.SameLine();
ImGui.TextUnformatted($"{this.Plugin.Manager.Page:N0}");
ImGui.SameLine();
using (ImGuiHelper.WithDisabled(loading || !this.Plugin.Manager.HasNext)) {
if (ImGuiHelper.IconButton(FontAwesomeIcon.ArrowRight)) {
this.Plugin.Manager.Page += 1;
}
}
}
}

View File

@ -180,6 +180,7 @@ enum GetDataResult {
V2 {
current: Option<Question>,
page: Vec<Question>,
has_next: bool,
},
}
@ -235,7 +236,7 @@ async fn get_data_v2(
from questions q
where q.publish_date <= current_timestamp
order by q.publish_date desc
limit $2::bigint + 1 offset $3::bigint * $2::bigint
limit $2::bigint + 2 offset $3::bigint * $2::bigint
"#,
user.id,
PER_PAGE as i64,
@ -258,7 +259,7 @@ async fn get_data_v2(
.try_collect::<Vec<_>>()
.await?;
let questions = questions.into_iter()
let mut questions: Vec<Question> = questions.into_iter()
.flat_map(|question| {
if question.active {
if include_current {
@ -296,8 +297,12 @@ async fn get_data_v2(
}
}
let has_next = questions.len() > PER_PAGE;
questions.truncate(PER_PAGE);
Ok(GetDataResult::V2 {
current,
has_next,
page: questions,
})
}