PSTeamSeas.psm1

Add-Type @"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
 
public class DonationOverview : INotifyPropertyChanged
{
    private int _totaldonations;
    private double _percentcomplete;
    private int _goal;
 
    public int TotalDonations
    {
        get { return _totaldonations; }
        set
        {
            _totaldonations = value;
            PercentComplete = Math.Round(((double)_totaldonations / Goal * 100), 2);
            OnPropertyChanged();
        }
    }
 
    public int Goal
    {
        get {return _goal; }
        set
        {
            _goal = value;
            OnPropertyChanged();
        }
    }
 
    public double PercentComplete
    {
        get {return _percentcomplete; }
        set
        {
            _percentcomplete = value;
            OnPropertyChanged();
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string caller = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(caller));
        }
    }
 
    public DonationOverview (int total, int goal)
    {
        Goal = goal;
        TotalDonations = total;
        PercentComplete = (Math.Round(((double)TotalDonations / Goal * 100), 2));
    }
}
"@

function Get-tsDonationInfo {
    [CmdletBinding()]
    param()

    Invoke-RestMethod -Uri "https://tscache.com/lb_recent.json"
}
function Get-tsTotalDonations {
    [CmdletBinding()]
    param(
        [int]$Goal = 30000000 
    )
    $totalDontions = Invoke-RestMethod -Uri "https://tscache.com/donation_total.json"
    [DonationOverview]::new($totalDontions.Count,$Goal)
}
function Show-tsTeamSeas {
    [CmdletBinding()]
    param()
    Add-Type -AssemblyName PresentationFramework

    $DataHash = [hashtable]::Synchronized(@{})
    $InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
    $DataSync = [System.Management.Automation.Runspaces.SessionStateVariableEntry]::new("DataHash", $DataHash, $Null)
    $InitialSessionState.Variables.Add($DataSync)

    $MaxThreads = 2
    $RunspacePool = [runspacefactory]::CreateRunspacePool(1,$MaxThreads,$InitialSessionState,$Host)
    $RunspacePool.ApartmentState = "STA"
    $RunspacePool.ThreadOptions = "ReuseThread"
    $RunspacePool.open()

    $RecentDonationsList =  [System.Collections.ObjectModel.ObservableCollection[Object]]::new()
    [System.Windows.Data.BindingOperations]::EnableCollectionSynchronization($RecentDonationsList, [System.Object]::new())

    $MainViewModel = [PSCustomObject]@{
        TotalDonations = Get-tsTotalDonations
        RecentDonations = $RecentDonationsList
    }
    $DataHash.MainViewModel = $MainViewModel
    $DataHash.ModuleBase = $MyInvocation.MyCommand.Module.ModuleBase

    $DataUpdateRunspace = New-UpdateDataRunspace
    $DataUpdateRunspace.RunspacePool = $RunspacePool
    [void]$DataUpdateRunspace.BeginInvoke()

    $PathToXAML = Join-Path $MyInvocation.MyCommand.Module.ModuleBase -ChildPath "WPF\MainWindow.xaml"
    $MainWindow = Import-XAML -PathToXAML $PathToXAML
    $MainWindow.DataContext = $DataHash.MainViewModel
    [void]$MainWindow.ShowDialog()
    $DataUpdateRunspace.Stop()
    $RunspacePool.Close()
    $RunspacePool.Dispose()
}
function Import-Xaml {
    param(
        $PathToXAML
    )
    Add-Type -AssemblyName PresentationFramework
    Add-Type -AssemblyName System.Windows.Forms
    [xml]$xaml = Get-Content -Path $PathToXAML
    $manager = [System.Xml.XmlNamespaceManager]::new($xaml.NameTable)
    $manager.AddNamespace("x","http://schemas.microsoft.com/winfx/2006/xaml")
    $xamlReader = [System.Xml.XmlNodeReader]::new($xaml)
    [Windows.Markup.XamlReader]::Load($xamlReader)
}
function New-UpdateDataRunspace {
    [CmdletBinding()]
    param()

    [powershell]::Create().AddScript{
        Try{
            $ErrorActionPreference = "Stop"
            Add-Type -AssemblyName PresentationFramework
            Add-Type -AssemblyName System.Windows.Forms

            #Import required assemblies and private functions
            Get-childItem -Path "$($DataHash.ModuleBase)\Private" -File -Recurse | ForEach-Object {Import-Module $_.FullName}
            Get-childItem -Path "$($DataHash.ModuleBase)\Public" -File -Recurse | ForEach-Object {Import-Module $_.FullName}
            Get-childItem -Path "$($DataHash.ModuleBase)\Classes" -File | ForEach-Object {Import-Module $_.FullName}

            Update-tsDonationData -ViewModel $DataHash.MainViewModel
        }
        catch{
            Show-Messagebox -Text $($_.Exception.Message) -Title "Data Runspace Error" -Icon Error
        }
    }
}
function Show-Messagebox {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Text,
        [string]$Title = "Message Box",
        [System.Windows.MessageBoxButton]$Buttons =[System.Windows.MessageBoxButton]::OK,
        [System.Windows.MessageBoxImage]$Icon = [System.Windows.MessageBoxImage]::None
    )

    [System.Windows.MessageBox]::Show($Text,$Title,$Buttons,$Icon)
}
function Update-tsDonationData {
    [CmdletBinding()]
    param(
        $ViewModel,
        [ValidateRange(5,100)]
        [int]$ListLength = 50
    )

    $TotalDonations = Get-tsTotalDonations
    $Recent = (Get-tsDonationInfo).Recent
    $TotalDonations.TotalDonations = $TotalDonations.TotalDonations - ($Recent | Measure-Object -Property pounds -Sum).Sum
    $ViewModel.TotalDonations.TotalDonations = $TotalDonations.TotalDonations

    foreach ($donation in $Recent){
        $ViewModel.TotalDonations.TotalDonations += $donation.pounds
        $ViewModel.RecentDonations.Insert(0,$donation)
        if ($ViewModel.RecentDonations.Count -gt $ListLength){
            $ViewModel.RecentDonations.RemoveAt($ViewModel.RecentDonations.Count - 1)
        }
        Start-Sleep -Seconds (Get-Random -Minimum 5 -Maximum 60)
    }
    Update-tsDonationData @PSBoundParameters
}
Export-ModuleMember -function Get-tsDonationInfo, Get-tsTotalDonations, Show-tsTeamSeas