Skip to content

Commit

Permalink
work on messages interface
Browse files Browse the repository at this point in the history
  • Loading branch information
kfrancis committed May 24, 2023
1 parent b2b4453 commit 28c570b
Show file tree
Hide file tree
Showing 21 changed files with 483 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public LocalizedString GetValue(string resourceKey)
var loc = _localizer[resourceKey];
if (loc.ResourceNotFound)
{
Debug.WriteLine($"Resource not found: {resourceKey}");
Debug.WriteLine($"L10N: Resource not found '{resourceKey}'");
loc = new LocalizedString(loc.Name, $"[{resourceKey}]", loc.ResourceNotFound);
}
return loc;
Expand Down
111 changes: 100 additions & 11 deletions src/NuSocial.Core/Models/User.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using NBitcoin;
using Nostr.Client.Keys;
using Nostr.Client.Keys;
using SQLite;
using SQLiteNetExtensions.Attributes;
using System.Text.Json.Serialization;

namespace NuSocial.Models;
Expand Down Expand Up @@ -117,8 +117,12 @@ public class UserConfiguration
/// <summary>
/// A contact on the #nostr network
/// </summary>
public sealed record Contact
public class Contact
{
[JsonIgnore]
[PrimaryKey, AutoIncrement]
public int Id { get; set; }

[JsonPropertyName("name")]
public Name Name { get; set; }

Expand All @@ -143,16 +147,86 @@ public override string ToString()
}
}

public class MessageData
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }

public DateTime When { get; set; }
public string Text { get; set; }
public bool IsRead { get; set; }
public bool IsIncoming { get; set; }

[ForeignKey(typeof(Message))]
public int MessageId { get; set; }

[ManyToOne]
public Message Message { get; set; }
}

public class Message
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }

[ForeignKey(typeof(Contact))]
public int ContactId { get; set; }

[ManyToOne]
public Contact? From { get; set; }

[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<MessageData> Messages { get; set; } = new();

public DateTime LatestMessageDate
{
get
{
if (Messages.Count > 0)
{
return Messages.OrderByDescending(x => x.When).FirstOrDefault()?.When ?? DateTime.Now;
}
else
{
return DateTime.Now;
}
}
}

[Ignore]
public string LatestMessage
{
get
{
if (Messages.Count > 0)
{
return Messages.OrderByDescending(x => x.When).FirstOrDefault()?.Text ?? string.Empty;
}
else
{
return string.Empty;
}
}
}
}

public class MessageContactRelationshipTable
{
public int ContactId { get; set; }
public int MessageId { get; set; }
}

/// <summary>
/// A simple model for the name of a contact.
/// </summary>
/// <param name="First">The first name of the contact.</param>
/// <param name="Last">The last name of the contact.</param>
public sealed record Name(
[property: JsonPropertyName("first")] string First,
[property: JsonPropertyName("last")] string Last)
public class Name
{
/// <inheritdoc/>
[JsonPropertyName("first")]
public string First { get; set; } = string.Empty;

[JsonPropertyName("last")]
public string Last { get; set; } = string.Empty;

public override string ToString()
{
return $"{First} {Last}";
Expand All @@ -162,5 +236,20 @@ public override string ToString()
/// <summary>
/// A simple model for the picture of a contact.
/// </summary>
/// <param name="Url">The URL of the picture.</param>
public sealed record Picture([property: JsonPropertyName("thumbnail")] Uri Url);
public class Picture
{
public Picture(Uri url)
{
Url = url;
}

public Picture()
{

}

[JsonPropertyName("thumbnail")]
public Uri Url { get; set; }

public string Blurhash { get; set; }
}
1 change: 1 addition & 0 deletions src/NuSocial.Core/NuSocial.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.141-beta" />
<PackageReference Include="SQLiteNetExtensions" Version="2.1.0" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.4" />
<PackageReference Include="System.Text.Json" Version="7.0.2" />
<PackageReference Include="Telerik.UI.for.Maui" Version="5.1.0" />
Expand Down
10 changes: 2 additions & 8 deletions src/NuSocial.Core/NuSocialCoreModule.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
using Microsoft.AppCenter;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration;
using NuSocial.Localization;
using NuSocial.Services;
using System.Diagnostics;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
Expand All @@ -25,7 +22,6 @@ public override void ConfigureServices(ServiceConfigurationContext context)

Configure<AbpVirtualFileSystemOptions>(options =>
{
// "YourRootNameSpace" is the root namespace of your project. It can be empty if your root namespace is empty.
options.FileSets.AddEmbedded<NuSocialCoreModule>("NuSocial.Core");
});

Expand Down Expand Up @@ -60,6 +56,4 @@ private static void ConfigureAnalytics(IServiceCollection services, IConfigurati
}
}
}


}
}
37 changes: 20 additions & 17 deletions src/NuSocial.Core/Services/LocalStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ namespace NuSocial.Services
public interface IDatabase
{
Task DeleteAllDataAsync();

Task<ObservableCollection<Message>> GetMessagesAsync();
Task<ObservableCollection<Relay>> GetRelaysAsync();

Task<ObservableCollection<User>> GetUsersAsync();

Task UpdateRelaysAsync(ObservableCollection<Relay> relays);
Task UpdateMessagesAsync(ObservableCollection<Message> relays);

Task UpdateUsersAsync(ObservableCollection<User> users);
}
Expand All @@ -30,9 +31,7 @@ public class LocalStorage : IDatabase, IAsyncDisposable

private const string _databaseFilename = "NuSocial.db3";
private readonly string _databasePath;
private readonly SemaphoreSlim _lock = new(1, 1);

private readonly SemaphoreSlim _semaphore = new(1, 1);
//private readonly SemaphoreSlim _lock = new(1, 1);

// create the database if it doesn't exist
private Task? _constructionTask;
Expand Down Expand Up @@ -60,11 +59,11 @@ public LocalStorage(string databasePath)

public async Task CloseDatabaseAsync()
{
await _lock.WaitAsync().ConfigureAwait(false);
//await _lock.WaitAsync();

if (_database == null)
{
_lock.Release();
//_lock.Release();
return;
}

Expand All @@ -75,7 +74,7 @@ public async Task CloseDatabaseAsync()
}
finally
{
_lock.Release();
//_lock.Release();
}
}

Expand All @@ -87,7 +86,7 @@ public async Task DeleteAllDataAsync()
// delete data
try
{
await _lock.WaitAsync().ConfigureAwait(false);
//await _lock.WaitAsync();

await Task.WhenAll(
//DeleteAllOfType<Service>(),
Expand All @@ -96,7 +95,7 @@ await Task.WhenAll(
}
finally
{
_lock.Release();
//_lock.Release();
}

// reset data versions
Expand All @@ -121,13 +120,13 @@ public async ValueTask DisposeAsync()
try
{
var db = await GetDatabaseConnection<T>(reset).ConfigureAwait(false);
await _lock.WaitAsync().ConfigureAwait(false);
//await _lock.WaitAsync();
List<T>? items = await AttemptAndRetry(() => { return db.Table<T>().ToListAsync(); }).ConfigureAwait(false);
return new ObservableCollection<T>(items);
}
finally
{
_lock.Release();
//_lock.Release();
}
}

Expand Down Expand Up @@ -155,8 +154,7 @@ protected virtual async Task DisposeAsync(bool disposing)

_constructionTask?.Dispose();
_constructionTask = null;
_semaphore?.Dispose();
_lock?.Dispose();
//_lock?.Dispose();
}

_isDisposed = true;
Expand Down Expand Up @@ -221,7 +219,7 @@ private async Task DropAndReset<T>(Action? reset = null)

try
{
await _lock.WaitAsync().ConfigureAwait(false);
//await _lock.WaitAsync();
var entityType = typeof(T);
var entityProperties = entityType.GetProperties();
var needsReset = false;
Expand Down Expand Up @@ -255,7 +253,7 @@ private async Task DropAndReset<T>(Action? reset = null)
}
finally
{
_lock.Release();
//_lock.Release();
}
}

Expand All @@ -267,17 +265,22 @@ private async Task UpdateIfPossible<T>(ObservableCollection<T> items, Action? re
try
{
var db = await GetDatabaseConnection<T>(reset).ConfigureAwait(false);
await _lock.WaitAsync().ConfigureAwait(false);
//await _lock.WaitAsync();
await AttemptAndRetry(() =>
{
return db.RunInTransactionAsync((dbc) => { foreach (var item in items) { dbc.InsertOrReplace(item); } });
}).ConfigureAwait(false);
}
finally
{
_lock.Release();
//_lock.Release();
}
}
}

public Task<ObservableCollection<Message>> GetMessagesAsync() => GetItemsAsync<Message>();


public Task UpdateMessagesAsync(ObservableCollection<Message> messages) => UpdateIfPossible(messages);
}
}
4 changes: 2 additions & 2 deletions src/NuSocial.Core/Services/NostrService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,8 @@ public void RegisterFilter(string subscription, NostrFilter filter)

public void StartNostr()
{
var faker = new Faker();
_timer = new Timer(SendNostrPostMessage, null, 0, faker.Random.Int(1000, 5000));
// var faker = new Faker();
//_timer = new Timer(SendNostrPostMessage, null, 0, faker.Random.Int(1000, 5000));
}

private void SendNostrPostMessage(object? state)
Expand Down
33 changes: 16 additions & 17 deletions src/NuSocial.Core/UsefulExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
namespace NuSocial.Core
namespace NuSocial.Core;

public static class ObservableCollectionExtensions
{
public static class ObservableCollectionExtensions
public static void RemoveLastN<T>(this ObservableCollection<T> collection, int n)
{
public static void RemoveLastN<T>(this ObservableCollection<T> collection, int n)
if (collection == null)
{
if (collection == null)
{
throw new ArgumentNullException(nameof(collection));
}
throw new ArgumentNullException(nameof(collection));
}

if (n < 0)
{
throw new ArgumentOutOfRangeException(nameof(n), "n must be non-negative");
}
if (n < 0)
{
throw new ArgumentOutOfRangeException(nameof(n), "n must be non-negative");
}

int removeCount = Math.Min(n, collection.Count);
int removeCount = Math.Min(n, collection.Count);

for (int i = 0; i < removeCount; i++)
{
collection.RemoveAt(collection.Count - 1);
}
for (int i = 0; i < removeCount; i++)
{
collection.RemoveAt(collection.Count - 1);
}
}
}
}
3 changes: 2 additions & 1 deletion src/NuSocial.Core/Validation/NostrKeyValidAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Nostr.Client.Keys;
using NuSocial.Localization;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.DependencyInjection;

namespace NuSocial.Core.Validation
{
Expand All @@ -19,7 +20,7 @@ protected override ValidationResult IsValid(object? value, ValidationContext val
}

var instance = validationContext.ObjectInstance;
var loc = (IStringLocalizer<NuSocialResource>?)instance.GetType().GetProperty("L")?.GetValue(instance);
var loc = (LocalizationResourceManager?)instance.GetType().GetProperty("L")?.GetValue(instance);
var invalidMessage = loc?["InvalidNostrKey"] ?? "Invalid Key";

if (value is string valueString && !string.IsNullOrEmpty(valueString))
Expand Down
Loading

0 comments on commit 28c570b

Please sign in to comment.