pushing stuff
This commit is contained in:
parent
cb4f70de6e
commit
8a38300cf1
@ -3,6 +3,8 @@ using Microsoft.UI.Xaml.Controls;
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using WinUIEx;
|
using WinUIEx;
|
||||||
|
using Microsoft.Windows.AppNotifications;
|
||||||
|
|
||||||
|
|
||||||
// To learn more about WinUI, the WinUI project structure,
|
// To learn more about WinUI, the WinUI project structure,
|
||||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||||
|
84
Bink.cs
84
Bink.cs
@ -1,4 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using Microsoft.UI.Xaml;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
@ -7,36 +10,89 @@ namespace wakka
|
|||||||
public class BinkPost
|
public class BinkPost
|
||||||
{
|
{
|
||||||
[JsonPropertyName("user")]
|
[JsonPropertyName("user")]
|
||||||
public string? User { get; set; }
|
public required string User { get; set; }
|
||||||
[JsonPropertyName("body")]
|
[JsonPropertyName("body")]
|
||||||
public string? Body { get; set; }
|
public required string Body { get; set; }
|
||||||
[JsonPropertyName("time")]
|
[JsonPropertyName("time")]
|
||||||
public long Time { get; set; }
|
public required long Time { get; set; }
|
||||||
public string TimeString { get; set; } = string.Empty;
|
public string TimeString { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Bink
|
public static class Bink
|
||||||
{
|
{
|
||||||
private static SshConnection Ssh { get; set; } = new SshConnection();
|
private static DispatcherTimer? timer = null;
|
||||||
|
public static readonly ObservableCollection<BinkPost> LoadedBinks = [];
|
||||||
|
private static List<BinkPost>? BinkData = null;
|
||||||
|
|
||||||
public void PostBink(string message)
|
public static void Initialize()
|
||||||
{
|
{
|
||||||
Ssh.RunCommandWithInput("town bink --pipe", message);
|
if (timer == null)
|
||||||
|
StartTimer();
|
||||||
|
if (BinkData == null)
|
||||||
|
{
|
||||||
|
BinkData = AllBinks();
|
||||||
|
if (BinkData != null)
|
||||||
|
{
|
||||||
|
foreach (var bink in BinkData)
|
||||||
|
{
|
||||||
|
SetBinkDateString(bink);
|
||||||
|
LoadedBinks.Add(bink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BinkPost>? AllBinks()
|
public static void PostBink(string message)
|
||||||
{
|
{
|
||||||
return JsonSerializer.Deserialize<List<BinkPost>>(Ssh.RunCommand("town bink --dump"));
|
SshConnection.RunCommandWithInput("town bink --pipe", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BinkPost>? BinksBefore(long TimeStamp)
|
public static List<BinkPost>? AllBinks()
|
||||||
{
|
{
|
||||||
return JsonSerializer.Deserialize<List<BinkPost>>(Ssh.RunCommand($"town bink --dump-before {TimeStamp}"));
|
return JsonSerializer.Deserialize<List<BinkPost>>(SshConnection.RunCommand("town bink --dump"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BinkPost>? BinksAfter(long TimeStamp)
|
public static List<BinkPost>? BinksBefore(long TimeStamp)
|
||||||
{
|
{
|
||||||
return JsonSerializer.Deserialize<List<BinkPost>>(Ssh.RunCommand($"town bink --dump-after {TimeStamp}"));
|
return JsonSerializer.Deserialize<List<BinkPost>>(SshConnection.RunCommand($"town bink --dump-before {TimeStamp}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<BinkPost>? BinksAfter(long TimeStamp)
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<List<BinkPost>>(SshConnection.RunCommand($"town bink --dump-after {TimeStamp}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetBinkDateString(BinkPost bink)
|
||||||
|
{
|
||||||
|
var date = DateTimeOffset.FromUnixTimeSeconds(bink.Time / 1000000000).DateTime.ToLocalTime();
|
||||||
|
bink.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetNewBinks()
|
||||||
|
{
|
||||||
|
var BinkList = BinksAfter(LoadedBinks[0].Time);
|
||||||
|
if (BinkList != null)
|
||||||
|
{
|
||||||
|
BinkList.Reverse();
|
||||||
|
foreach (var bink in BinkList)
|
||||||
|
{
|
||||||
|
SetBinkDateString(bink);
|
||||||
|
LoadedBinks.Insert(0, bink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void StartTimer()
|
||||||
|
{
|
||||||
|
timer = new DispatcherTimer();
|
||||||
|
timer.Interval = TimeSpan.FromSeconds(20);
|
||||||
|
timer.Tick += Timer_Tick;
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Timer_Tick(object? sender, object? e)
|
||||||
|
{
|
||||||
|
GetNewBinks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<CommandBar DefaultLabelPosition="Right" Grid.Row="0">
|
<CommandBar DefaultLabelPosition="Right" Grid.Row="0">
|
||||||
<AppBarButton Icon="Refresh" Label="Update" Click="GetNewBinksButton" />
|
<AppBarButton Icon="Refresh" Label="Update" Click="RefreshButton" />
|
||||||
<AppBarButton Icon="Add" Label="Post" Click="OnBinkCreate" />
|
<AppBarButton Icon="Add" Label="Post" Click="OnBinkCreateButton" />
|
||||||
</CommandBar>
|
</CommandBar>
|
||||||
|
|
||||||
<ContentDialog
|
<ContentDialog
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Navigation;
|
|
||||||
using Org.BouncyCastle.Tls;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Threading;
|
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using System;
|
||||||
|
|
||||||
// To learn more about WinUI, the WinUI project structure,
|
// To learn more about WinUI, the WinUI project structure,
|
||||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||||
@ -18,44 +12,12 @@ namespace wakka
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class BinkPage : Page
|
public sealed partial class BinkPage : Page
|
||||||
{
|
{
|
||||||
private DispatcherTimer timer;
|
|
||||||
|
|
||||||
private readonly ObservableCollection<BinkPost> Binks = [];
|
|
||||||
private static Bink Bink { get; set; } = new Bink();
|
|
||||||
|
|
||||||
public BinkPage()
|
public BinkPage()
|
||||||
{
|
{
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
StartTimer();
|
binksListView.ItemsSource = Bink.LoadedBinks;
|
||||||
var BinkList = Bink.AllBinks();
|
|
||||||
if (BinkList != null)
|
|
||||||
{
|
|
||||||
foreach (var bink in BinkList)
|
|
||||||
{
|
|
||||||
SetBinkDateString(bink);
|
|
||||||
Binks.Add(bink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binksListView.ItemsSource = Binks;
|
|
||||||
}
|
|
||||||
public void SetBinkDateString (BinkPost bink)
|
|
||||||
{
|
|
||||||
var date = DateTimeOffset.FromUnixTimeSeconds(bink.Time / 1000000000).DateTime.ToLocalTime();
|
|
||||||
bink.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)");
|
|
||||||
}
|
|
||||||
public void GetNewBinks()
|
|
||||||
{
|
|
||||||
var BinkList = Bink.BinksAfter(Binks[0].Time);
|
|
||||||
if (BinkList != null)
|
|
||||||
{
|
|
||||||
BinkList.Reverse();
|
|
||||||
foreach (var bink in BinkList)
|
|
||||||
{
|
|
||||||
SetBinkDateString(bink);
|
|
||||||
Binks.Insert(0, bink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BinkSubmit(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
private void BinkSubmit(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||||
{
|
{
|
||||||
var message = binkComposeBox.Text;
|
var message = binkComposeBox.Text;
|
||||||
@ -63,10 +25,10 @@ namespace wakka
|
|||||||
{
|
{
|
||||||
Bink.PostBink(message);
|
Bink.PostBink(message);
|
||||||
binkComposeBox.Text = string.Empty;
|
binkComposeBox.Text = string.Empty;
|
||||||
GetNewBinks();
|
Bink.GetNewBinks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(binkComposeBox.Text))
|
if (string.IsNullOrEmpty(binkComposeBox.Text))
|
||||||
@ -79,27 +41,16 @@ namespace wakka
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnBinkCreate(object sender, RoutedEventArgs e)
|
private async void OnBinkCreateButton(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
binkComposeDialog.IsPrimaryButtonEnabled = false;
|
binkComposeDialog.IsPrimaryButtonEnabled = false;
|
||||||
await binkComposeDialog.ShowAsync();
|
await binkComposeDialog.ShowAsync();
|
||||||
}
|
}
|
||||||
public void GetNewBinksButton(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
public void RefreshButton(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
GetNewBinks();
|
Bink.GetNewBinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartTimer()
|
|
||||||
{
|
|
||||||
timer = new DispatcherTimer();
|
|
||||||
timer.Interval = TimeSpan.FromSeconds(20);
|
|
||||||
timer.Tick += Timer_Tick;
|
|
||||||
timer.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Timer_Tick(object? sender, object? e)
|
|
||||||
{
|
|
||||||
GetNewBinks();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
139
Feels.cs
139
Feels.cs
@ -1,44 +1,157 @@
|
|||||||
using System.Collections.Generic;
|
using Microsoft.UI.Xaml;
|
||||||
|
using Renci.SshNet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Windows.ApplicationModel.VoiceCommands;
|
||||||
|
using Windows.Storage.Search;
|
||||||
|
|
||||||
namespace wakka
|
namespace wakka
|
||||||
{
|
{
|
||||||
public class FeelsPost
|
public class FeelsPost
|
||||||
{
|
{
|
||||||
[JsonPropertyName("user")]
|
[JsonPropertyName("user")]
|
||||||
public string? User { get; set; }
|
public required string User { get; set; }
|
||||||
[JsonPropertyName("path")]
|
[JsonPropertyName("path")]
|
||||||
public string? Path { get; set; }
|
public required string Path { get; set; }
|
||||||
[JsonPropertyName("m_time")]
|
[JsonPropertyName("m_time")]
|
||||||
public long M_Time { get; set; }
|
public required long M_Time { get; set; }
|
||||||
|
[JsonPropertyName("reported_date")]
|
||||||
|
public required long ReportedDate { get; set; }
|
||||||
public string TimeString { get; set; } = string.Empty;
|
public string TimeString { get; set; } = string.Empty;
|
||||||
public string Body { get; set; } = string.Empty;
|
public string Body { get; set; } = string.Empty;
|
||||||
|
|
||||||
public int WordCount { get; set; } = 0;
|
public int WordCount { get; set; } = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Feels
|
public static class Feels
|
||||||
{
|
{
|
||||||
private static SshConnection Ssh { get; set; } = new SshConnection();
|
public static readonly ObservableCollection<FeelsPost> LoadedFeelsPosts = [];
|
||||||
|
private static DispatcherTimer? Timer = null;
|
||||||
|
private static List<List<FeelsPost>>? LoadTimeMetadata = null;
|
||||||
|
private static int CurrentChunk = 0;
|
||||||
|
|
||||||
public List<FeelsPost>? AllFeels()
|
public static void Initialize()
|
||||||
{
|
{
|
||||||
return JsonSerializer.Deserialize<List<FeelsPost>>(Ssh.RunCommand("~nebula/bin/dumpfeels"));
|
if (Timer == null)
|
||||||
|
StartTimer();
|
||||||
|
if (LoadTimeMetadata == null)
|
||||||
|
{
|
||||||
|
var feels = AllFeels();
|
||||||
|
if (feels != null)
|
||||||
|
{
|
||||||
|
LoadTimeMetadata = (List<List<FeelsPost>>)feels.Chunk(10).Select(chunk => chunk.ToList()).ToList();
|
||||||
|
LoadFeelsChunk();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeelsPost>? FeelsAfter(long TimeStamp)
|
public static void LoadFeelsChunk()
|
||||||
{
|
{
|
||||||
return JsonSerializer.Deserialize<List<FeelsPost>>(Ssh.RunCommand($"~nebula/bin/dumpfeels --after {TimeStamp}"));
|
if (LoadTimeMetadata == null)
|
||||||
|
return;
|
||||||
|
var chunk = LoadTimeMetadata[CurrentChunk];
|
||||||
|
foreach (var feel in chunk)
|
||||||
|
{
|
||||||
|
ConstructFeel(feel);
|
||||||
|
LoadedFeelsPosts.Add(feel);
|
||||||
|
}
|
||||||
|
CurrentChunk++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeelsPost>? FeelsFromUser(string User, List<FeelsPost> Feels)
|
private static void StartTimer()
|
||||||
|
{
|
||||||
|
Timer = new DispatcherTimer();
|
||||||
|
Timer.Interval = TimeSpan.FromSeconds(20);
|
||||||
|
Timer.Tick += Timer_Tick;
|
||||||
|
Timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Timer_Tick(object? sender, object? e)
|
||||||
|
{
|
||||||
|
GetNewFeels();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetNewFeels()
|
||||||
|
{
|
||||||
|
var newFeels = FeelsAfter(LoadedFeelsPosts[0].M_Time);
|
||||||
|
if (newFeels != null)
|
||||||
|
{
|
||||||
|
var additions = new List<FeelsPost>();
|
||||||
|
foreach (var newFeel in newFeels)
|
||||||
|
{
|
||||||
|
ConstructFeel(newFeel);
|
||||||
|
FeelsPost? toRemove = null;
|
||||||
|
foreach (var liveFeel in LoadedFeelsPosts)
|
||||||
|
{
|
||||||
|
if (liveFeel.Path.Equals(newFeel.Path))
|
||||||
|
{
|
||||||
|
toRemove = liveFeel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toRemove != null)
|
||||||
|
LoadedFeelsPosts.Remove(toRemove);
|
||||||
|
additions.Add(newFeel);
|
||||||
|
}
|
||||||
|
additions.Reverse();
|
||||||
|
foreach (var feel in additions)
|
||||||
|
{
|
||||||
|
LoadedFeelsPosts.Insert(0, feel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetTodayFeelPath()
|
||||||
|
{
|
||||||
|
var dateString = DateTime.Now.ToString("yyyyMMdd");
|
||||||
|
return $"/home/{SshConnection.User}/.ttbp/entries/{dateString}.txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetTodayFeelBody()
|
||||||
|
{
|
||||||
|
|
||||||
|
return SshConnection.RunCommand($"cat {GetTodayFeelPath()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PostFeel(string body)
|
||||||
|
{
|
||||||
|
SshConnection.RunCommandWithInput($"cat > {GetTodayFeelPath()}", body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FeelsPost>? AllFeels()
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<List<FeelsPost>>(SshConnection.RunCommand("~nebula/bin/dumpfeels"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FeelsPost>? FeelsAfter(long TimeStamp)
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<List<FeelsPost>>(SshConnection.RunCommand($"~nebula/bin/dumpfeels --after {TimeStamp}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FeelsPost>? FeelsFromUser(string User, List<FeelsPost> Feels)
|
||||||
{
|
{
|
||||||
return Feels.FindAll(i => i.User == User);
|
return Feels.FindAll(i => i.User == User);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetFeelsBody(FeelsPost Post)
|
public static string GetFeelsBody(FeelsPost Post)
|
||||||
{
|
{
|
||||||
return Ssh.RunCommand($"cat {Post.Path}");
|
return SshConnection.RunCommand($"cat {Post.Path}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConstructFeel(FeelsPost feel)
|
||||||
|
{
|
||||||
|
var date = DateTimeOffset.FromUnixTimeSeconds(feel.M_Time).DateTime.ToLocalTime();
|
||||||
|
feel.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)");
|
||||||
|
var body = GetFeelsBody(feel);
|
||||||
|
char[] delimiters = new char[] { ' ', '\n' };
|
||||||
|
feel.WordCount = body.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Length;
|
||||||
|
feel.Body = body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<ScrollViewer x:Name="scrollViewer" ViewChanged="ViewChanged">
|
<ScrollViewer x:Name="scrollViewer" ViewChanged="ViewChanged">
|
||||||
<ListView Grid.Row="0" x:Name="feelsListView" SelectionMode="None">
|
<ListView x:Name="feelsListView" SelectionMode="None">
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate x:DataType="local:FeelsPost">
|
<DataTemplate x:DataType="local:FeelsPost">
|
||||||
<Expander Width="600" Margin="0,10,0,10" IsExpanded="True" CornerRadius="8">
|
<Expander HorizontalAlignment="Left" MaxWidth="1200" Margin="0,10,0,10" IsExpanded="True" CornerRadius="8">
|
||||||
<Expander.Header>
|
<Expander.Header>
|
||||||
<StackPanel Margin="10,10,10,10" HorizontalAlignment="Left">
|
<StackPanel Margin="10,10,10,10" HorizontalAlignment="Left">
|
||||||
<StackPanel Padding="0,0,0,5" Orientation="Horizontal">
|
<StackPanel Padding="0,0,0,5" Orientation="Horizontal">
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.Windows.AppNotifications;
|
||||||
|
|
||||||
// To learn more about WinUI, the WinUI project structure,
|
// To learn more about WinUI, the WinUI project structure,
|
||||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||||
@ -14,34 +16,10 @@ namespace wakka
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class FeelsFeedPage : Page
|
public sealed partial class FeelsFeedPage : Page
|
||||||
{
|
{
|
||||||
private readonly Feels Feels = new Feels();
|
|
||||||
private readonly ObservableCollection<FeelsPost> LiveFeelsPosts = [];
|
|
||||||
private readonly List<List<FeelsPost>> AllFeels;
|
|
||||||
private int CurrentChunk = 0;
|
|
||||||
|
|
||||||
public FeelsFeedPage()
|
public FeelsFeedPage()
|
||||||
{
|
{
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
var feels = Feels.AllFeels();
|
feelsListView.ItemsSource = Feels.LoadedFeelsPosts;
|
||||||
AllFeels = (List<List<FeelsPost>>)feels.Chunk(4).Select(chunk => chunk.ToList()).ToList();
|
|
||||||
LoadFeelsChunk();
|
|
||||||
feelsListView.ItemsSource = LiveFeelsPosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadFeelsChunk()
|
|
||||||
{
|
|
||||||
var chunk = AllFeels[CurrentChunk];
|
|
||||||
foreach (var feel in chunk)
|
|
||||||
{
|
|
||||||
var date = DateTimeOffset.FromUnixTimeSeconds(feel.M_Time).DateTime.ToLocalTime();
|
|
||||||
feel.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)");
|
|
||||||
var body = Feels.GetFeelsBody(feel);
|
|
||||||
char[] delimiters = new char[] { ' ', '\n' };
|
|
||||||
feel.WordCount = body.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Length;
|
|
||||||
feel.Body = body;
|
|
||||||
LiveFeelsPosts.Add(feel);
|
|
||||||
}
|
|
||||||
CurrentChunk++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
|
private void ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
|
||||||
@ -51,7 +29,7 @@ namespace wakka
|
|||||||
{
|
{
|
||||||
if (scrollViewer.VerticalOffset >= scrollViewer.ScrollableHeight)
|
if (scrollViewer.VerticalOffset >= scrollViewer.ScrollableHeight)
|
||||||
{
|
{
|
||||||
LoadFeelsChunk();
|
Feels.LoadFeelsChunk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,34 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<SelectorBar Grid.Row="0" x:Name="feelsSelectorBar" SelectionChanged="SelectorChanged">
|
<Grid Grid.Row="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<SelectorBar Grid.Column="0" x:Name="feelsSelectorBar" SelectionChanged="SelectorChanged">
|
||||||
<SelectorBarItem x:Name="feedSelectorBarItem" Text="Feed" IsSelected="True" />
|
<SelectorBarItem x:Name="feedSelectorBarItem" Text="Feed" IsSelected="True" />
|
||||||
<!--<SelectorBarItem x:Name="usersSelectorBarItem" Text="Users" />-->
|
<!--<SelectorBarItem x:Name="usersSelectorBarItem" Text="Users" />-->
|
||||||
</SelectorBar>
|
</SelectorBar>
|
||||||
|
<CommandBar Grid.Column="1" DefaultLabelPosition="Right" HorizontalAlignment="Right" x:Name="feelsCommandBar">
|
||||||
|
<AppBarButton Icon="Add" Label="New Feel" Click="OnFeelsCreateButton"/>
|
||||||
|
</CommandBar>
|
||||||
|
</Grid>
|
||||||
<Frame Grid.Row="1" x:Name="FeelsNavigationFrame" IsNavigationStackEnabled="False" />
|
<Frame Grid.Row="1" x:Name="FeelsNavigationFrame" IsNavigationStackEnabled="False" />
|
||||||
|
<ContentDialog
|
||||||
|
x:Name="feelsComposeDialog"
|
||||||
|
Title="New Feels"
|
||||||
|
PrimaryButtonText="Post"
|
||||||
|
CloseButtonText="Cancel"
|
||||||
|
PrimaryButtonClick="OnFeelsSubmitButton">
|
||||||
|
<TextBox
|
||||||
|
PlaceholderText="Your feels here..."
|
||||||
|
Width="700"
|
||||||
|
Height="300"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
TextChanged="OnTextChanged"
|
||||||
|
x:Name="feelsComposeBox"/>
|
||||||
|
</ContentDialog>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
||||||
|
@ -1,18 +1,5 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices.WindowsRuntime;
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.Foundation.Collections;
|
|
||||||
using Microsoft.UI.Xaml;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
using System;
|
||||||
using Microsoft.UI.Xaml.Data;
|
|
||||||
using Microsoft.UI.Xaml.Input;
|
|
||||||
using Microsoft.UI.Xaml.Media;
|
|
||||||
using Microsoft.UI.Xaml.Navigation;
|
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
|
||||||
|
|
||||||
// To learn more about WinUI, the WinUI project structure,
|
// To learn more about WinUI, the WinUI project structure,
|
||||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||||
@ -33,5 +20,44 @@ namespace wakka
|
|||||||
{
|
{
|
||||||
FeelsNavigationFrame.Navigate(typeof(FeelsFeedPage));
|
FeelsNavigationFrame.Navigate(typeof(FeelsFeedPage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void OnFeelsCreateButton(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var path = Feels.GetTodayFeelPath();
|
||||||
|
if (SshConnection.DoesFileExist(path))
|
||||||
|
{
|
||||||
|
feelsComposeBox.Text = SshConnection.RunCommand($"cat {path}");
|
||||||
|
feelsComposeDialog.IsPrimaryButtonEnabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
feelsComposeBox.Text = string.Empty;
|
||||||
|
feelsComposeDialog.IsPrimaryButtonEnabled = false;
|
||||||
|
}
|
||||||
|
await feelsComposeDialog.ShowAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFeelsSubmitButton(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||||
|
{
|
||||||
|
var message = feelsComposeBox.Text;
|
||||||
|
if (!string.IsNullOrEmpty(message))
|
||||||
|
{
|
||||||
|
Feels.PostFeel(message);
|
||||||
|
feelsComposeBox.Text = string.Empty;
|
||||||
|
Feels.GetNewFeels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(feelsComposeBox.Text))
|
||||||
|
{
|
||||||
|
feelsComposeDialog.IsPrimaryButtonEnabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
feelsComposeDialog.IsPrimaryButtonEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,18 +13,19 @@ namespace wakka
|
|||||||
|
|
||||||
public sealed partial class MainWindow : Window
|
public sealed partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
private static SshConnection Ssh { get; set; } = new SshConnection();
|
|
||||||
public Frame RootFrame;
|
public Frame RootFrame;
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
RootFrame = rootFrame;
|
RootFrame = rootFrame;
|
||||||
Ssh.DeleteSshKey();
|
//Ssh.DeleteSshKey();
|
||||||
if (Ssh.KeyExists() & (string)App.LocalSettingsData.Values["username"] != null)
|
if (SshConnection.KeyExists() & (string)App.LocalSettingsData.Values["username"] != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Ssh.InitializeConnection((string)App.LocalSettingsData.Values["username"]);
|
SshConnection.InitializeConnection((string)App.LocalSettingsData.Values["username"]);
|
||||||
|
Bink.Initialize();
|
||||||
|
Feels.Initialize();
|
||||||
RootFrame.Content = new NavigationPage();
|
RootFrame.Content = new NavigationPage();
|
||||||
}
|
}
|
||||||
catch (Renci.SshNet.Common.SshAuthenticationException)
|
catch (Renci.SshNet.Common.SshAuthenticationException)
|
||||||
|
@ -34,10 +34,12 @@ namespace wakka
|
|||||||
{
|
{
|
||||||
if (selectedItem == binkPageNav)
|
if (selectedItem == binkPageNav)
|
||||||
{
|
{
|
||||||
|
Bink.GetNewBinks();
|
||||||
navigationFrame.Navigate(typeof(BinkPage));
|
navigationFrame.Navigate(typeof(BinkPage));
|
||||||
}
|
}
|
||||||
else if (selectedItem == feelsPageNav)
|
else if (selectedItem == feelsPageNav)
|
||||||
{
|
{
|
||||||
|
Feels.GetNewFeels();
|
||||||
navigationFrame.Navigate(typeof(FeelsNavigationPage));
|
navigationFrame.Navigate(typeof(FeelsNavigationPage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,14 @@
|
|||||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||||
|
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||||
|
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||||
IgnorableNamespaces="uap rescap">
|
IgnorableNamespaces="uap rescap">
|
||||||
|
|
||||||
<Identity
|
<Identity
|
||||||
Name="8edc9fec-3276-4986-bbf6-5074643d2fdc"
|
Name="8edc9fec-3276-4986-bbf6-5074643d2fdc"
|
||||||
Publisher="CN=helix"
|
Publisher="CN=helixnebula"
|
||||||
Version="1.0.0.0" />
|
Version="0.0.1.0" />
|
||||||
|
|
||||||
<mp:PhoneIdentity PhoneProductId="8edc9fec-3276-4986-bbf6-5074643d2fdc" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
<mp:PhoneIdentity PhoneProductId="8edc9fec-3276-4986-bbf6-5074643d2fdc" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||||
|
|
||||||
@ -42,6 +44,23 @@
|
|||||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square71x71Logo="Assets\SmallTile.png" Square310x310Logo="Assets\LargeTile.png"/>
|
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square71x71Logo="Assets\SmallTile.png" Square310x310Logo="Assets\LargeTile.png"/>
|
||||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||||
</uap:VisualElements>
|
</uap:VisualElements>
|
||||||
|
<Extensions>
|
||||||
|
|
||||||
|
<!--Specify which CLSID to activate when notification is clicked-->
|
||||||
|
<desktop:Extension Category="windows.toastNotificationActivation">
|
||||||
|
<desktop:ToastNotificationActivation ToastActivatorCLSID="9DF6E26B-F9A8-40B3-AD41-AF83E4A07921" />
|
||||||
|
</desktop:Extension>
|
||||||
|
|
||||||
|
<!--Register COM CLSID-->
|
||||||
|
<com:Extension Category="windows.comServer">
|
||||||
|
<com:ComServer>
|
||||||
|
<com:ExeServer Executable="SampleApp\SampleApp.exe" DisplayName="SampleApp" Arguments="----AppNotificationActivated:">
|
||||||
|
<com:Class Id="9DF6E26B-F9A8-40B3-AD41-AF83E4A07921" />
|
||||||
|
</com:ExeServer>
|
||||||
|
</com:ComServer>
|
||||||
|
</com:Extension>
|
||||||
|
|
||||||
|
</Extensions>
|
||||||
</Application>
|
</Application>
|
||||||
</Applications>
|
</Applications>
|
||||||
|
|
||||||
|
@ -1,19 +1,14 @@
|
|||||||
using Org.BouncyCastle.Crypto;
|
using Renci.SshNet;
|
||||||
using Org.BouncyCastle.Crypto.Generators;
|
|
||||||
using Org.BouncyCastle.OpenSsl;
|
|
||||||
using Org.BouncyCastle.Security;
|
|
||||||
using Renci.SshNet;
|
|
||||||
using Renci.SshNet.Common;
|
using Renci.SshNet.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Windows.Media.Protection.PlayReady;
|
|
||||||
|
|
||||||
namespace wakka
|
namespace wakka
|
||||||
{
|
{
|
||||||
public class SshConnection
|
public static class SshConnection
|
||||||
{
|
{
|
||||||
public static string User { get; set; } = string.Empty;
|
public static string User { get; set; } = string.Empty;
|
||||||
|
|
||||||
@ -25,9 +20,9 @@ namespace wakka
|
|||||||
|
|
||||||
public static string? PublicKey { get; set; } = null;
|
public static string? PublicKey { get; set; } = null;
|
||||||
|
|
||||||
public bool KeyExists() => File.Exists(SshKeyPath);
|
public static bool KeyExists() => File.Exists(SshKeyPath);
|
||||||
|
|
||||||
public void InitializeConnection(string user)
|
public static void InitializeConnection(string user)
|
||||||
{
|
{
|
||||||
if (!File.Exists(SshKeyPath) || user == string.Empty)
|
if (!File.Exists(SshKeyPath) || user == string.Empty)
|
||||||
{
|
{
|
||||||
@ -50,7 +45,7 @@ namespace wakka
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string RunCommand(string command)
|
public static string RunCommand(string command)
|
||||||
{
|
{
|
||||||
if (Client == null || !Client.IsConnected)
|
if (Client == null || !Client.IsConnected)
|
||||||
{
|
{
|
||||||
@ -60,7 +55,18 @@ namespace wakka
|
|||||||
return rc.Result;
|
return rc.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void RunCommandWithInput(string command, string input)
|
public static bool DoesFileExist(string path)
|
||||||
|
{
|
||||||
|
if (Client == null || !Client.IsConnected)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("SSH client is not connected.");
|
||||||
|
}
|
||||||
|
var command = Client.CreateCommand($"test -e {path} && echo 1 || echo 0");
|
||||||
|
var result = command.Execute();
|
||||||
|
return result.Trim() == "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async void RunCommandWithInput(string command, string input)
|
||||||
{
|
{
|
||||||
if (Client == null || !Client.IsConnected)
|
if (Client == null || !Client.IsConnected)
|
||||||
{
|
{
|
||||||
@ -79,7 +85,7 @@ namespace wakka
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CreateSshKey()
|
public static string CreateSshKey()
|
||||||
{
|
{
|
||||||
var keygen = new SshKeyGenerator.SshKeyGenerator(2048);
|
var keygen = new SshKeyGenerator.SshKeyGenerator(2048);
|
||||||
var privateKey = keygen.ToPrivateKey();
|
var privateKey = keygen.ToPrivateKey();
|
||||||
@ -87,7 +93,7 @@ namespace wakka
|
|||||||
return keygen.ToRfcPublicKey("wakka");
|
return keygen.ToRfcPublicKey("wakka");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteSshKey()
|
public static void DeleteSshKey()
|
||||||
{
|
{
|
||||||
if (File.Exists(SshKeyPath))
|
if (File.Exists(SshKeyPath))
|
||||||
{
|
{
|
||||||
|
@ -2,12 +2,10 @@ using Microsoft.UI.Xaml;
|
|||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Renci.SshNet.Common;
|
using Renci.SshNet.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Windows.Storage.Pickers;
|
using Windows.Storage.Pickers;
|
||||||
using WinRT.Interop;
|
using WinRT.Interop;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
// To learn more about WinUI, the WinUI project structure,
|
// To learn more about WinUI, the WinUI project structure,
|
||||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||||
|
|
||||||
@ -19,8 +17,6 @@ namespace wakka
|
|||||||
|
|
||||||
public sealed partial class StartupSshPage : Page
|
public sealed partial class StartupSshPage : Page
|
||||||
{
|
{
|
||||||
private static SshConnection Ssh { get; set; } = new SshConnection();
|
|
||||||
|
|
||||||
public StartupSshPage()
|
public StartupSshPage()
|
||||||
{
|
{
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
@ -58,7 +54,7 @@ namespace wakka
|
|||||||
|
|
||||||
private void CreateSshKey(object sender, RoutedEventArgs e)
|
private void CreateSshKey(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var publicKey = Ssh.CreateSshKey();
|
var publicKey = SshConnection.CreateSshKey();
|
||||||
if (publicKey != null)
|
if (publicKey != null)
|
||||||
{
|
{
|
||||||
var dataPackage = new DataPackage();
|
var dataPackage = new DataPackage();
|
||||||
@ -66,7 +62,6 @@ namespace wakka
|
|||||||
Clipboard.SetContent(dataPackage);
|
Clipboard.SetContent(dataPackage);
|
||||||
sshKeyCreateButton.Content = "Public key copied!";
|
sshKeyCreateButton.Content = "Public key copied!";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||||
@ -98,7 +93,9 @@ namespace wakka
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Ssh.InitializeConnection((string)App.LocalSettingsData.Values["username"]);
|
SshConnection.InitializeConnection((string)App.LocalSettingsData.Values["username"]);
|
||||||
|
Bink.Initialize();
|
||||||
|
Feels.Initialize();
|
||||||
var mainWindow = (App.Current as App)?.m_window;
|
var mainWindow = (App.Current as App)?.m_window;
|
||||||
if (mainWindow != null)
|
if (mainWindow != null)
|
||||||
{
|
{
|
||||||
|
13
wakka.csproj
13
wakka.csproj
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||||
@ -94,5 +94,16 @@
|
|||||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||||
|
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
||||||
|
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
|
||||||
|
<PackageCertificateThumbprint>158AC0CEA4875FEA7A385A58844BE2EA095E5FCE</PackageCertificateThumbprint>
|
||||||
|
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
|
||||||
|
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
||||||
|
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
|
||||||
|
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
||||||
|
<AppxBundle>Always</AppxBundle>
|
||||||
|
<AppxBundlePlatforms>x86|x64|arm64</AppxBundlePlatforms>
|
||||||
|
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||||
|
<LangVersion>12.0</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user