much changes

main
resneptacle 3 weeks ago
parent e7e71ff820
commit bf18ded213

@ -1,6 +1,6 @@
using Mindmagma.Curses;
namespace ANSI_Fahrplan;
namespace Fahrplan;
public class AsciiArt {
/// <summary>

@ -1,9 +1,8 @@
#nullable disable
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
using Newtonsoft.Json;
namespace Fahrplan;
namespace Fahrplan.Plan;
public class Root {
[JsonProperty("$schema")]

@ -0,0 +1,57 @@
using Newtonsoft.Json;
using System.Net;
namespace Fahrplan.Network;
/// <summary>
/// Class to help get the plan from the CCC API
/// </summary>
public class PlanPuller () {
public const string PlanJsonUrl = "https://fahrplan.events.ccc.de/congress/2024/fahrplan/schedule/export/schedule.json";
public const string LocalPlanFilename = "ansi-fahrplan.json";
/// <summary>
/// Pulls the current fahrplan, stores it in a temp
/// directory and returns the parsed JSON object.
/// If another plan already exists in the temp directory
/// and is not older than three minutes, a new plan
/// will not yet be pulled to save on web requests
/// </summary>
/// <param name="forcePull">If true, skips checking the timestamp on the plan cache</param>
/// <returns>Parsed Fahrplan JSON object</returns>
public async static Task<Plan.Root> GetFahrplanAsync (bool forcePull = false) {
var localPlanFileFullpath =
Path.GetTempPath () +
LocalPlanFilename;
if (File.Exists (localPlanFileFullpath)) {
var fileInfo = new FileInfo (localPlanFileFullpath);
// File is not older than three minutes, return cached file
if (fileInfo.LastWriteTime + TimeSpan.FromMinutes (3) > DateTime.Now) {
var reader = fileInfo.OpenText ();
var content = await reader.ReadToEndAsync ();
return JsonConvert.DeserializeObject<Plan.Root> (content);
}
}
var httpClient = new HttpClient ();
// Be a good netizen, add a proper UA string
httpClient.DefaultRequestHeaders.Add ("User-Agent", "AnsiFahrplan/1.0 (by Snep, c3@diskcat.com)");
var response = await httpClient.GetAsync (new Uri (PlanJsonUrl));
response.EnsureSuccessStatusCode ();
var responseContent = await response.Content.ReadAsStringAsync ();
try {
File.WriteAllText (localPlanFileFullpath, responseContent);
} catch (Exception ex) {
Console.Error.WriteLine ("Warning: Failed to write Plan cache file: " + ex.Message);
}
return JsonConvert.DeserializeObject<Plan.Root> (responseContent);
}
}

@ -1,9 +1,10 @@
using SCI.CursesWrapper;
using SCI.CursesWrapper.UiElements;
using ANSI_Fahrplan.Screens;
using Fahrplan.Screens;
using Mindmagma.Curses;
using Fahrplan.Plan;
namespace ANSI_Fahrplan;
namespace Fahrplan;
class Program {
private static void Main (string [] args) {
@ -46,6 +47,9 @@ class Program {
introScreen.RegisterInputHandler (inputHandler);
introScreen.SetWindowActive ();
// Whilst the intro screen is shown, get the Fahrplan
var fahrplan = Network.PlanPuller.GetFahrplanAsync ().Result;
// Wait until intro screen is closed
while (introScreen.WindowId > -1) Thread.Sleep (50); // TODO; Unjank this
introScreen = null;
@ -55,7 +59,8 @@ class Program {
footerWindow.DrawFooter ("Fahrplan", "LLLeft", "RRRRRight");
// -- Create menu bar -- //
var topMenu = new TopMenu (screen, inputHandler, CreateMenuItems (contentWindow));
var menuItems = CreateMenuItems (contentWindow, footerWindow, fahrplan.schedule.conference);
var topMenu = new TopMenu (screen, inputHandler, menuItems);
topMenu.ActivateItem (topMenu.MenuItems [1]);
// Wait until the input handler routine stops
@ -66,12 +71,16 @@ class Program {
Environment.Exit (1);
}
private static List<MenuItem> CreateMenuItems (ContentWindow contentWindow) {
private static List<MenuItem> CreateMenuItems (
ContentWindow contentWindow,
FooterWindow footer,
Plan.Conference planConference
) {
var helpItem = new MenuItem ("Help", "F1");
var upcomingItem = new MenuItem ("Upcoming", "F2");
var byDayItem = new MenuItem ("By Day", "F3");
var byRoomItem = new MenuItem ("By Room", "F4");
var bySpeakerItem = new MenuItem ("By Speaker", "F5");
var upcomingItem = new MenuItem ("Upcoming", "u");
var byDayItem = new MenuItem ("By Day", "d");
var byRoomItem = new MenuItem ("By Room", "r");
var bySpeakerItem = new MenuItem ("By Speaker", "s");
var quitItem = new MenuItem ("Quit (C-q)");
helpItem.OnItemActivated += (object sender, MenuItemActivatedEventArgs e) => {
@ -84,6 +93,23 @@ class Program {
upcomingItem.OnItemActivated += (object sender, MenuItemActivatedEventArgs e) => {
var scrollWindow = contentWindow.CreateInnerScrollWindow ();
scrollWindow.AddContent ("-- Upcoming --");
scrollWindow.RenderCurrentViewport ();
};
byRoomItem.OnItemActivated += (object sender, MenuItemActivatedEventArgs e) => {
var scrollWindow = contentWindow.CreateInnerScrollWindow ();
footer.DrawFooter (" Day 1 ->");
// TODO: Do the actual foo-magic of formatting the plan as a nice text table
// and key handling to switch between days
foreach (var day in planConference.days) {
scrollWindow.AddContent (DateTime.Parse (day.date).ToString ("dd.MM.yyyy") + $" (Day {day.index})");
foreach (var room in day.rooms) {
scrollWindow.AddContent ($"- {room.Key}");
}
}
scrollWindow.RenderCurrentViewport ();
};

@ -1,6 +1,6 @@
using SCI.CursesWrapper;
namespace ANSI_Fahrplan.Screens;
namespace Fahrplan.Screens;
public class IntroScreen : Window {
/// <summary>

@ -0,0 +1,10 @@
- [] Ensure minimum width and height of terminal
- [] Help text
- [] Actually format the different views as text and display them
- [] One class per view to store data in?
- [] Key events per view, like switching days
- [] Footer text
- [] Colors
- [] Cleanup
- [] Make a TCP service out of this somehow

@ -3,6 +3,10 @@ using Mindmagma.Curses;
namespace SCI.CursesWrapper.UiElements;
public class FooterWindow : Window {
private string leftText = "";
private string rightText = "";
private string titleText = "";
/// <summary>
/// Class constructor
/// </summary>
@ -24,36 +28,40 @@ public class FooterWindow : Window {
/// <param name="title"></param>
/// <param name="left"></param>
/// <param name="right"></param>
public void DrawFooter (string title, string left = "", string right = "") {
public void DrawFooter (string? title = null, string? left = null, string? right = null) {
Clear ();
if (title is not null) titleText = title;
if (left is not null) leftText = left;
if (right is not null) rightText = right;
// TODO: Describe the last-character-in-window bug(fix) here
var pad =
(WindowSize.Width / 2) -
(title.Length / 2)
(titleText.Length / 2)
- 1;
var finalString =
" " + left.PadRight (pad) +
title +
(string.IsNullOrEmpty (right)?
" " + leftText.PadRight (pad) +
titleText +
(string.IsNullOrEmpty (rightText)?
"" :
right.PadLeft (pad)
rightText.PadLeft (pad)
);
// String too long, leave out left and right text
if (finalString.Length > WindowSize.Width - 1) {
finalString = " ".PadLeft (pad) + title;
finalString = " ".PadLeft (pad) + titleText;
}
// String still too long, leave out the padding and left align title
if (finalString.Length > WindowSize.Width - 1) {
finalString = " " + title;
finalString = " " + titleText;
}
// String still too long, cut to size
if (finalString.Length > WindowSize.Width - 1) {
finalString = title.Substring (0, WindowSize.Width - 1);
finalString = titleText.Substring (0, WindowSize.Width - 1);
}
try {

Loading…
Cancel
Save