diff --git a/Chiota/Chiota.Android/Chiota.Android.csproj b/Chiota/Chiota.Android/Chiota.Android.csproj
index 70229e0..4c2e8db 100644
--- a/Chiota/Chiota.Android/Chiota.Android.csproj
+++ b/Chiota/Chiota.Android/Chiota.Android.csproj
@@ -94,9 +94,6 @@
2.0.2
-
- 3.0.0-beta14
-
@@ -114,8 +111,8 @@
-
-
+
+
diff --git a/Chiota/Chiota.Android/MainActivity.cs b/Chiota/Chiota.Android/MainActivity.cs
index 3909f94..bfd01e2 100644
--- a/Chiota/Chiota.Android/MainActivity.cs
+++ b/Chiota/Chiota.Android/MainActivity.cs
@@ -1,24 +1,31 @@
namespace Chiota.Droid
{
using Android.App;
+ using Android.App.Job;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Chiota;
using Chiota.Droid.Services;
- using Chiota.Messages;
- using ImageCircle.Forms.Plugin.Droid;
- using Plugin.LocalNotifications;
+ using ImageCircle.Forms.Plugin.Droid;
using Plugin.Permissions;
using Xamarin.Forms;
- [Activity(Label = "FlorenceApp", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
+ [Activity(Label = "Chiota", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
+ private JobScheduler jobScheduler;
+
+ public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
+ {
+ ZXing.Net.Mobile.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
+ PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
@@ -27,45 +34,26 @@ protected override void OnCreate(Bundle bundle)
// ToolbarResource = Resource.Id.toolbar;
base.OnCreate(bundle);
- Xamarin.Forms.Forms.Init(this, bundle);
+ Forms.Init(this, bundle);
+
+ this.jobScheduler = (JobScheduler)this.GetSystemService(JobSchedulerService);
ZXing.Net.Mobile.Forms.Android.Platform.Init();
ImageCircleRenderer.Init();
- // Changes the notification icon
- LocalNotificationsImplementation.NotificationIconId = Resource.Drawable.reminder;
-
this.LoadApplication(new App());
this.WireUpLongRunningTask();
}
- // https://github.com/jamesmontemagno/MediaPlugin#important-permission-information
- public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
+ private void WireUpLongRunningTask()
{
- ZXing.Net.Mobile.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
- PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
- }
-
- public void WireUpLongRunningTask()
- {
- MessagingCenter.Subscribe(
- this,
- "StartLongRunningTaskMessage",
- message =>
- {
- var intent = new Intent(this, typeof(PeriodicTaskService));
- this.StartService(intent);
- });
-
- MessagingCenter.Subscribe(
- this,
- "StopLongRunningTaskMessage",
- message =>
- {
- var intent = new Intent(this, typeof(PeriodicTaskService));
- this.StopService(intent);
- });
+ var javaClass = Java.Lang.Class.FromType(typeof(PeriodicJob));
+ var compName = new ComponentName(this, javaClass);
+ var jobInfo = new JobInfo.Builder(1, compName)
+ .SetRequiredNetworkType(NetworkType.Any)
+ .SetPeriodic(1000 * 60 * 15).Build();
+ var result = this.jobScheduler.Schedule(jobInfo);
}
}
}
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/Properties/AndroidManifest.xml b/Chiota/Chiota.Android/Properties/AndroidManifest.xml
index c7bb1ae..3f249c7 100644
--- a/Chiota/Chiota.Android/Properties/AndroidManifest.xml
+++ b/Chiota/Chiota.Android/Properties/AndroidManifest.xml
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/Chiota/Chiota.Android/Resources/Resource.designer.cs b/Chiota/Chiota.Android/Resources/Resource.designer.cs
index 2d99489..556e0d1 100644
--- a/Chiota/Chiota.Android/Resources/Resource.designer.cs
+++ b/Chiota/Chiota.Android/Resources/Resource.designer.cs
@@ -26,7 +26,6 @@ static Resource()
public static void UpdateIdValues()
{
- global::Plugin.LocalNotifications.Resource.Drawable.plugin_lc_smallicon = global::Chiota.Droid.Resource.Drawable.plugin_lc_smallicon;
global::Xamarin.Forms.Platform.Android.Resource.Attribute.actionBarSize = global::Chiota.Droid.Resource.Attribute.actionBarSize;
global::ZXing.Net.Mobile.Forms.Android.Resource.Layout.zxingscanneractivitylayout = global::Chiota.Droid.Resource.Layout.zxingscanneractivitylayout;
global::ZXing.Net.Mobile.Forms.Android.Resource.Layout.zxingscannerfragmentlayout = global::Chiota.Droid.Resource.Layout.zxingscannerfragmentlayout;
@@ -2355,26 +2354,26 @@ public partial class Drawable
// aapt resource value: 0x7f020053
public const int avd_hide_password = 2130837587;
+ // aapt resource value: 0x7f020135
+ public const int avd_hide_password_1 = 2130837813;
+
// aapt resource value: 0x7f020136
- public const int avd_hide_password_1 = 2130837814;
+ public const int avd_hide_password_2 = 2130837814;
// aapt resource value: 0x7f020137
- public const int avd_hide_password_2 = 2130837815;
-
- // aapt resource value: 0x7f020138
- public const int avd_hide_password_3 = 2130837816;
+ public const int avd_hide_password_3 = 2130837815;
// aapt resource value: 0x7f020054
public const int avd_show_password = 2130837588;
+ // aapt resource value: 0x7f020138
+ public const int avd_show_password_1 = 2130837816;
+
// aapt resource value: 0x7f020139
- public const int avd_show_password_1 = 2130837817;
+ public const int avd_show_password_2 = 2130837817;
// aapt resource value: 0x7f02013a
- public const int avd_show_password_2 = 2130837818;
-
- // aapt resource value: 0x7f02013b
- public const int avd_show_password_3 = 2130837819;
+ public const int avd_show_password_3 = 2130837818;
// aapt resource value: 0x7f020055
public const int design_bottom_navigation_item_background = 2130837589;
@@ -3021,11 +3020,11 @@ public partial class Drawable
// aapt resource value: 0x7f02012b
public const int notification_icon_background = 2130837803;
- // aapt resource value: 0x7f020134
- public const int notification_template_icon_bg = 2130837812;
+ // aapt resource value: 0x7f020133
+ public const int notification_template_icon_bg = 2130837811;
- // aapt resource value: 0x7f020135
- public const int notification_template_icon_low_bg = 2130837813;
+ // aapt resource value: 0x7f020134
+ public const int notification_template_icon_low_bg = 2130837812;
// aapt resource value: 0x7f02012c
public const int notification_tile_bg = 2130837804;
@@ -3034,22 +3033,19 @@ public partial class Drawable
public const int notify_panel_notification_icon_bg = 2130837805;
// aapt resource value: 0x7f02012e
- public const int plugin_lc_smallicon = 2130837806;
+ public const int plus = 2130837806;
// aapt resource value: 0x7f02012f
- public const int plus = 2130837807;
+ public const int reminder = 2130837807;
// aapt resource value: 0x7f020130
- public const int reminder = 2130837808;
+ public const int splash_screen = 2130837808;
// aapt resource value: 0x7f020131
- public const int splash_screen = 2130837809;
+ public const int tooltip_frame_dark = 2130837809;
// aapt resource value: 0x7f020132
- public const int tooltip_frame_dark = 2130837810;
-
- // aapt resource value: 0x7f020133
- public const int tooltip_frame_light = 2130837811;
+ public const int tooltip_frame_light = 2130837810;
static Drawable()
{
diff --git a/Chiota/Chiota.Android/Services/BackgroundReceiver.cs b/Chiota/Chiota.Android/Services/BackgroundReceiver.cs
deleted file mode 100644
index 02bd003..0000000
--- a/Chiota/Chiota.Android/Services/BackgroundReceiver.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-namespace Chiota.Droid.Services
-{
- using System.Linq;
-
- using Android.Content;
- using Android.OS;
-
- using Chiota.Models;
- using Chiota.Services;
-
- using Plugin.LocalNotifications;
-
- [BroadcastReceiver]
- public class BackgroundReceiver : BroadcastReceiver
- {
- public override async void OnReceive(Context context, Intent intent)
- {
- var pm = (PowerManager)context.GetSystemService(Context.PowerService);
- var wakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "BackgroundReceiver");
- wakeLock.Acquire();
-
- // seed needs to be stored on device!!
- var secureStorage = new SecureStorage();
- if (secureStorage.CheckUserStored())
- {
- var user = await secureStorage.GetUser();
- if (user != null)
- {
- var contactApprovedList = await user.TangleMessenger.GetJsonMessageAsync>(user.ApprovedAddress);
-
- // Todo also message for a new contact request
- foreach (var contact in contactApprovedList.Where(c => !c.Data.Rejected))
- {
- var encryptedMessages = await user.TangleMessenger.GetMessagesAsync(contact.Data.ChatAdress);
- foreach (var unused in encryptedMessages.Where(c => !c.Stored))
- {
- CrossLocalNotifications.Current.Show(contact.Data.Name, "New Message from " + contact.Data.Name);
- }
- }
- }
- }
-
- wakeLock.Release();
- }
- }
-}
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/Services/NotificationsTask.cs b/Chiota/Chiota.Android/Services/NotificationsTask.cs
new file mode 100644
index 0000000..a0cb9ea
--- /dev/null
+++ b/Chiota/Chiota.Android/Services/NotificationsTask.cs
@@ -0,0 +1,61 @@
+namespace Chiota.Droid.Services
+{
+ using System.Linq;
+ using System.Threading.Tasks;
+
+ using Android.App;
+ using Android.Content;
+ using Android.Media;
+ using Android.OS;
+ using Android.Support.V4.App;
+
+ using Chiota.Models;
+ using Chiota.Services;
+ using Java.Lang;
+
+ using Resource = Resource;
+
+ public class NotificationsTask : AsyncTask>
+ {
+ protected override async Task RunInBackground(params Void[] @params)
+ {
+ var finished = await this.LookForNewNotifications();
+ return finished;
+ }
+
+ private async Task LookForNewNotifications()
+ {
+ // seed needs to be stored on device!!
+ var secureStorage = new SecureStorage();
+ if (secureStorage.CheckUserStored())
+ {
+ var user = await secureStorage.GetUser();
+ if (user != null)
+ {
+ var contactApprovedList = await user.TangleMessenger.GetJsonMessageAsync>(user.ApprovedAddress);
+
+ // currently no messages for contact request due to perfomance issues
+ foreach (var contact in contactApprovedList.Where(c => !c.Data.Rejected))
+ {
+ var encryptedMessages = await user.TangleMessenger.GetMessagesAsync(contact.Data.ChatAdress);
+
+ foreach (var unused in encryptedMessages.Where(c => !c.Stored))
+ {
+ var builder = new NotificationCompat.Builder(Application.Context)
+ .SetAutoCancel(true) // Dismiss from the notif. area when clicked
+ .SetContentTitle(contact.Data.Name) // Set its title
+ .SetContentText("New Message from " + contact.Data.Name)
+ .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
+ .SetSmallIcon(Resource.Drawable.reminder);
+ var notification = builder.Build();
+ var notificationManager = Application.Context.GetSystemService(Context.NotificationService) as NotificationManager;
+ notificationManager?.Notify(0, notification);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/Chiota/Chiota.Android/Services/PeriodicJob.cs b/Chiota/Chiota.Android/Services/PeriodicJob.cs
new file mode 100644
index 0000000..13de8aa
--- /dev/null
+++ b/Chiota/Chiota.Android/Services/PeriodicJob.cs
@@ -0,0 +1,63 @@
+namespace Chiota.Droid.Services
+{
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ using Android.App;
+ using Android.App.Job;
+ using Android.OS;
+
+ using Chiota.Messages;
+
+ using Xamarin.Forms;
+
+ [Service(Name = "ChiotaApp.ChiotaApp.PeriodicJob", Permission = "android.permission.BIND_JOB_SERVICE")]
+ public class PeriodicJob : JobService
+ {
+ private CancellationTokenSource cts;
+
+ public override bool OnStartJob(JobParameters jobParameters)
+ {
+ // Called by the operating system when starting the service.
+ // Start up a thread, do work on the thread.
+ this.cts = new CancellationTokenSource();
+
+ Task.Run(
+ () =>
+ {
+ try
+ {
+ var notification = new NotificationsTask();
+ notification.Execute();
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ finally
+ {
+ if (this.cts.IsCancellationRequested)
+ {
+ var message = new CancelledMessage();
+ Device.BeginInvokeOnMainThread(() => MessagingCenter.Send(message, "CancelledMessage"));
+ }
+ }
+ },
+ this.cts.Token);
+
+ return true;
+ }
+
+ public override bool OnStopJob(JobParameters jobParameters)
+ {
+ // Called by Android when it has to terminate a running service.
+ if (this.cts != null)
+ {
+ this.cts.Token.ThrowIfCancellationRequested();
+
+ this.cts.Cancel();
+ }
+
+ return true; // false don't reschedule the job.
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/Services/PeriodicTaskService.cs b/Chiota/Chiota.Android/Services/PeriodicTaskService.cs
deleted file mode 100644
index 4295962..0000000
--- a/Chiota/Chiota.Android/Services/PeriodicTaskService.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-namespace Chiota.Droid.Services
-{
- using System.Threading;
- using System.Threading.Tasks;
-
- using Android.App;
- using Android.Content;
- using Android.OS;
- using Android.Runtime;
-
- using Chiota.Messages;
-
- using Xamarin.Forms;
-
- //Todo https://blog.xamarin.com/replacing-services-jobs-android-oreo-8-0/
- [Service]
- public class PeriodicTaskService : Service
- {
- private CancellationTokenSource cts;
-
- public override IBinder OnBind(Intent intent)
- {
- return null;
- }
-
- public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
- {
- this.cts = new CancellationTokenSource();
-
- Task.Run(
- () =>
- {
- try
- {
- // start backgroundreceiver
- var alarmIntent = new Intent(this, typeof(BackgroundReceiver));
-
- var pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
-
- var alarmManager = this.GetSystemService(AlarmService).JavaCast();
-
- // alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + 3 * 1000, pending);
- alarmManager.SetRepeating(
- AlarmType.RtcWakeup,
- SystemClock.ElapsedRealtime(),
- 1000 * 60 * 15, // updates every 15 minutes
- pending);
- }
- catch (OperationCanceledException)
- {
- }
- finally
- {
- if (this.cts.IsCancellationRequested)
- {
- var message = new CancelledMessage();
- Device.BeginInvokeOnMainThread(() => MessagingCenter.Send(message, "CancelledMessage"));
- }
- }
- },
- this.cts.Token);
-
- return StartCommandResult.Sticky;
- }
-
- public override void OnDestroy()
- {
- if (this.cts != null)
- {
- this.cts.Token.ThrowIfCancellationRequested();
-
- this.cts.Cancel();
- }
-
- base.OnDestroy();
- }
- }
-}
\ No newline at end of file
diff --git a/Chiota/Chiota.UWP/Chiota.UWP.csproj b/Chiota/Chiota.UWP/Chiota.UWP.csproj
index fce6780..04376bb 100644
--- a/Chiota/Chiota.UWP/Chiota.UWP.csproj
+++ b/Chiota/Chiota.UWP/Chiota.UWP.csproj
@@ -151,9 +151,6 @@
2.0.2
-
- 3.0.0-beta14
-
2.5.1.444934
diff --git a/Chiota/Chiota.UWP/MainPage.xaml.cs b/Chiota/Chiota.UWP/MainPage.xaml.cs
index f50d6ec..291b205 100644
--- a/Chiota/Chiota.UWP/MainPage.xaml.cs
+++ b/Chiota/Chiota.UWP/MainPage.xaml.cs
@@ -1,45 +1,74 @@
namespace Chiota.UWP
{
using System;
- using System.Linq;
+ using System.Diagnostics;
using System.Threading.Tasks;
- using Chiota.Models;
- using Chiota.Services;
-
- using Plugin.LocalNotifications;
-
using Windows.ApplicationModel.Background;
- using Windows.UI.Xaml;
///
- /// An empty page that can be used on its own or navigated to within a Frame.
+ /// The main page.
///
public sealed partial class MainPage
{
+ private const string BackgroundTaskName = "MyBackgroundTask";
+
public MainPage()
{
this.InitializeComponent();
+
+ // ApplicationView.PreferredLaunchViewSize = new Size(600, 850);
+ // ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
+
this.LoadApplication(new Chiota.App());
ZXing.Net.Mobile.Forms.WindowsUniversal.ZXingScannerViewRenderer.Init();
if (this.IsRegistered())
{
- this.Deregister();
+ this.Unregister();
}
- this.Loaded += this.MainPageLoaded;
+ this.Register();
}
- private async void MainPageLoaded(object sender, RoutedEventArgs e)
+ private async Task Register()
{
- await this.BackgroundTask();
+ BackgroundExecutionManager.RemoveAccess();
+
+ await BackgroundExecutionManager.RequestAccessAsync();
+
+ var builder = new BackgroundTaskBuilder
+ {
+ Name = BackgroundTaskName,
+ TaskEntryPoint =
+ "UWPRuntimeComponent.BackgroundTask"
+ };
+
+ // builder.SetTrigger(new SystemTrigger(SystemTriggerType.InternetAvailable, false));
+ builder.SetTrigger(new TimeTrigger(15, false));
+
+ var task = builder.Register();
+
+ task.Completed += this.Task_Completed;
+
+ Debug.WriteLine("[PeriodicBackgroundService] Background task registered");
+ }
+
+ private async void Task_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
+ {
+ var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
+ var key = BackgroundTaskName;
+ var message = settings.Values[key];
+
+ // Run your background task code here
+ // notification here
+ Debug.WriteLine("[PeriodicBackgroundService] Background task completed");
}
- private void Deregister()
+ private void Unregister()
{
- var taskName = "BackgroundTask";
+ var taskName = BackgroundTaskName;
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
@@ -52,7 +81,7 @@ private void Deregister()
private bool IsRegistered()
{
- var taskName = "BackgroundTask";
+ var taskName = BackgroundTaskName;
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
@@ -64,50 +93,5 @@ private bool IsRegistered()
return false;
}
-
- private async Task BackgroundTask()
- {
- BackgroundExecutionManager.RemoveAccess();
-
- await BackgroundExecutionManager.RequestAccessAsync();
-
- var builder = new BackgroundTaskBuilder
- {
- Name = "BackgroundTask",
- TaskEntryPoint = "UWPRuntimeComponent.BackgroundTask"
- };
-
- builder.SetTrigger(new TimeTrigger(15, false));
- var task = builder.Register();
- task.Completed += this.TaskCompleted;
- }
-
- private async void TaskCompleted(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
- {
- var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
- var key = "BackgroundTask";
- var message = settings.Values[key].ToString();
-
- // Run your background task code here
- var secureStorage = new SecureStorage();
- if (secureStorage.CheckUserStored())
- {
- var user = await secureStorage.GetUser();
- if (user != null)
- {
- var contactApprovedList = await user.TangleMessenger.GetJsonMessageAsync>(user.ApprovedAddress);
-
- // Todo also message for a new contact request
- foreach (var contact in contactApprovedList.Where(c => !c.Data.Rejected))
- {
- var encryptedMessages = await user.TangleMessenger.GetMessagesAsync(contact.Data.ChatAdress);
- foreach (var unused in encryptedMessages.Where(c => !c.Stored))
- {
- CrossLocalNotifications.Current.Show(contact.Data.Name, "New Message from " + contact.Data.Name);
- }
- }
- }
- }
- }
}
}
diff --git a/Chiota/Chiota/App.xaml.cs b/Chiota/Chiota/App.xaml.cs
index 0c4ae10..31395e7 100644
--- a/Chiota/Chiota/App.xaml.cs
+++ b/Chiota/Chiota/App.xaml.cs
@@ -4,7 +4,6 @@
namespace Chiota
{
- using Chiota.Messages;
using Chiota.Services;
using Chiota.Views;
@@ -28,10 +27,6 @@ public App()
protected override async void OnStart()
{
- // starts listening for messages
- var messagestart = new StartLongRunningTaskMessage();
- MessagingCenter.Send(messagestart, "StartLongRunningTaskMessage");
-
var secureStorage = new SecureStorage();
if (secureStorage.CheckUserStored())
{
diff --git a/Chiota/Chiota/Chiota.csproj b/Chiota/Chiota/Chiota.csproj
index dad5bc9..913fecb 100644
--- a/Chiota/Chiota/Chiota.csproj
+++ b/Chiota/Chiota/Chiota.csproj
@@ -30,7 +30,6 @@
-
diff --git a/Chiota/Chiota/IOTAServices/IOTAHelper.cs b/Chiota/Chiota/IOTAServices/IOTAHelper.cs
index 97d6a31..3aba0af 100644
--- a/Chiota/Chiota/IOTAServices/IOTAHelper.cs
+++ b/Chiota/Chiota/IOTAServices/IOTAHelper.cs
@@ -9,6 +9,8 @@
using Chiota.Services;
using Chiota.ViewModels;
+ using Newtonsoft.Json;
+
using Tangle.Net.Entity;
using VTDev.Libraries.CEXEngine.Crypto.Cipher.Asymmetric.Encrypt.NTRU;
@@ -16,6 +18,12 @@
public class IotaHelper
{
+ public static TryteString ObjectToTryteString(T data)
+ {
+ var serializeObject = JsonConvert.SerializeObject(data);
+ return TryteString.FromAsciiString(serializeObject);
+ }
+
public static bool CorrectSeedAdressChecker(string seed)
{
if (seed == null)
@@ -59,6 +67,7 @@ public static async Task> GetNewMessages(IAsymmetricKeyPa
var messages = new List();
var encryptedMessages = await tangle.GetMessagesAsync(contact.ChatAdress);
var messageList = FilterChatMessages(encryptedMessages, keyPair);
+
if (messageList != null)
{
var sortedMessageList = messageList.OrderBy(o => o.Date).ToList();
@@ -68,7 +77,7 @@ public static async Task> GetNewMessages(IAsymmetricKeyPa
{
Text = message.Message,
IsIncoming = message.Signature == contact.PublicKeyAdress.Substring(0, 30),
- MessagDateTime = message.Date,
+ MessagDateTime = message.Date.ToLocalTime(),
ProfileImage = contact.ImageUrl
});
}
diff --git a/Chiota/Chiota/IOTAServices/TangleMessenger.cs b/Chiota/Chiota/IOTAServices/TangleMessenger.cs
index adb9cb8..a63d4a4 100644
--- a/Chiota/Chiota/IOTAServices/TangleMessenger.cs
+++ b/Chiota/Chiota/IOTAServices/TangleMessenger.cs
@@ -30,21 +30,27 @@ public TangleMessenger(Seed seed)
public List ShorStorageHashes { get; set; }
- public async Task SendMessageAsync(TryteString message, string address)
+ public async Task SendMessageAsync(TryteString message, string address, int retryNumber = 3)
{
- var bundle = new Bundle();
- bundle.AddTransfer(this.CreateTransfer(message, address));
+ var roundNumber = 0;
+ while (roundNumber < retryNumber)
+ {
+ this.UpdateNode(roundNumber);
- await Task.Factory.StartNew(() => this.repository.SendTransfer(this.seed, bundle, SecurityLevel.Medium, 27, 14));
- }
+ var bundle = new Bundle();
+ bundle.AddTransfer(this.CreateTransfer(message, address));
- public async Task SendJsonMessageAsync(SentDataWrapper data, string address)
- {
- var serializeObject = JsonConvert.SerializeObject(data);
- var bundle = new Bundle();
- bundle.AddTransfer(this.CreateTransfer(TryteString.FromAsciiString(serializeObject), address));
-
- await Task.Factory.StartNew(() => this.repository.SendTransfer(this.seed, bundle, SecurityLevel.Medium, 27, 14));
+ try
+ {
+ await Task.Factory.StartNew(
+ () => this.repository.SendTransfer(this.seed, bundle, SecurityLevel.Medium, 27, 14));
+ break;
+ }
+ catch
+ {
+ roundNumber++;
+ }
+ }
}
public async Task> GetMessagesAsync(string adresse, int retryNumber = 1)
@@ -53,11 +59,7 @@ public async Task> GetMessagesAsync(string adresse, int
var messagesList = new List();
while (roundNumber < retryNumber && messagesList.Count == 0)
{
- // try to update the repository
- if (roundNumber > 0)
- {
- this.repository = new RepositoryFactory().Create();
- }
+ this.UpdateNode(roundNumber);
var adresses = new List { new Address(adresse) };
var transactions = await this.repository.FindTransactionsByAddressesAsync(adresses);
@@ -83,9 +85,71 @@ public async Task> GetMessagesAsync(string adresse, int
return messagesList;
}
- public TryteString GetMessages(Bundle bundle)
+ public async Task> GetJsonMessageAsync(string adresse, int retryNumber = 1)
+ {
+ var roundNumber = 0;
+ var messagesList = new List();
+
+ while (roundNumber < retryNumber && messagesList.Count == 0)
+ {
+ this.UpdateNode(roundNumber);
+
+ var adresses = new List { new Address(adresse) };
+ var transactions = await this.repository.FindTransactionsByAddressesAsync(adresses);
+
+ // store hashes and load only new bundles
+ var newHashes = IotaHelper.GetNewHashes(transactions, this.ShorStorageHashes);
+ foreach (var transactionsHash in newHashes)
+ {
+ this.ShorStorageHashes.Add(transactionsHash);
+
+ var hashString = transactionsHash.ToString();
+ if (Application.Current.Properties.ContainsKey(hashString))
+ {
+ var messageString = Application.Current.Properties[hashString] as string;
+ var deserializedObject = JsonConvert.DeserializeObject(messageString);
+ messagesList.Add(deserializedObject);
+ }
+ else
+ {
+ var bundle = await this.repository.GetBundleAsync(transactionsHash);
+ var messages = bundle.GetMessages();
+ foreach (var message in messages)
+ {
+ try
+ {
+ var deserializedObject = JsonConvert.DeserializeObject(message);
+ messagesList.Add(deserializedObject);
+ Application.Current.Properties[hashString] = message;
+ await Application.Current.SavePropertiesAsync();
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+ }
+ }
+
+ roundNumber++;
+ }
+
+ return messagesList;
+ }
+
+ private void UpdateNode(int roundNumber)
+ {
+ if (roundNumber > 0)
+ {
+ this.repository = new RepositoryFactory().Create();
+ }
+ }
+
+ private TryteString GetMessages(Bundle bundle)
{
var messageTrytes = string.Empty;
+
+ // multiple message per bundle?
foreach (var transaction in bundle.Transactions)
{
if (transaction.Value < 0)
@@ -99,38 +163,19 @@ public TryteString GetMessages(Bundle bundle)
}
}
- if (!messageTrytes.Contains("9ENDEGUTALLESGUT9"))
+ if (!messageTrytes.Contains(ChiotaIdentifier.End))
{
return null;
}
- var index = messageTrytes.IndexOf("9ENDEGUTALLESGUT9", StringComparison.Ordinal);
+ var index = messageTrytes.IndexOf(ChiotaIdentifier.End, StringComparison.Ordinal);
return new TryteString(messageTrytes.Substring(0, index));
}
- public async Task> GetJsonMessageAsync(string adresse)
- {
- var adresses = new List { new Address(adresse) };
- var transactions = await this.repository.FindTransactionsByAddressesAsync(adresses);
- var messagesList = new List();
- foreach (var transactionsHash in transactions.Hashes)
- {
- var bundle = this.repository.GetBundle(transactionsHash);
-
- var messages = bundle.GetMessages();
- foreach (var message in messages)
- {
- messagesList.Add(JsonConvert.DeserializeObject(message));
- }
- }
-
- return messagesList;
- }
-
private async Task MessageFromBundleOrStorage(Hash transactionsHash)
{
// todo upload them again after snapshot
- TryteStringMessage message = new TryteStringMessage();
+ var message = new TryteStringMessage();
var hashString = transactionsHash.ToString();
if (Application.Current.Properties.ContainsKey(hashString))
{
@@ -158,7 +203,7 @@ private Transfer CreateTransfer(TryteString message, string adress)
{
Address = new Address(adress),
Message = message,
- Tag = new Tag("CHIOTAYOURIOTACHATAPP"),
+ Tag = new Tag(ChiotaIdentifier.Tag),
Timestamp = Timestamp.UnixSecondsTimestamp
};
}
diff --git a/Chiota/Chiota/Models/ChiotaIdentifier.cs b/Chiota/Chiota/Models/ChiotaIdentifier.cs
index 4d3e111..f40fc52 100644
--- a/Chiota/Chiota/Models/ChiotaIdentifier.cs
+++ b/Chiota/Chiota/Models/ChiotaIdentifier.cs
@@ -9,5 +9,7 @@ public class ChiotaIdentifier
public static string FirstBreak => "9CHIOTAYOUR9";
public static string SecondBreak => "9IOTACHATAPP9";
+
+ public static string Tag => "CHIOTAYOURIOTACHATAPP";
}
}
diff --git a/Chiota/Chiota/ViewModels/AddContactViewModel.cs b/Chiota/Chiota/ViewModels/AddContactViewModel.cs
index 0fb6025..f17fd0f 100644
--- a/Chiota/Chiota/ViewModels/AddContactViewModel.cs
+++ b/Chiota/Chiota/ViewModels/AddContactViewModel.cs
@@ -8,6 +8,8 @@
using Chiota.Models;
using Chiota.Services;
+ using Newtonsoft.Json;
+
using Tangle.Net.Entity;
using Xamarin.Forms;
@@ -118,7 +120,8 @@ private async Task AddContact()
};
// encrypt contact request? too much infos needed here for one message needs to get request adress plus chatadress
- await this.user.TangleMessenger.SendJsonMessageAsync(new SentDataWrapper { Data = requestContact, Sender = this.user.Name }, contacts[0].ContactAdress);
+ var sentData = new SentDataWrapper { Data = requestContact, Sender = this.user.Name };
+ await this.user.TangleMessenger.SendMessageAsync(IotaHelper.ObjectToTryteString(sentData), contacts[0].ContactAdress);
this.SuccessfulRequestPrompt();
}
}
diff --git a/Chiota/Chiota/ViewModels/ChatViewModel.cs b/Chiota/Chiota/ViewModels/ChatViewModel.cs
index 0427727..4085165 100644
--- a/Chiota/Chiota/ViewModels/ChatViewModel.cs
+++ b/Chiota/Chiota/ViewModels/ChatViewModel.cs
@@ -9,7 +9,6 @@
using System.Windows.Input;
using Chiota.IOTAServices;
- using Chiota.Messages;
using Chiota.Models;
using Chiota.Services;
@@ -26,6 +25,8 @@ public class ChatViewModel : BaseViewModel
public Action DisplayInvalidPublicKeyPrompt;
+ private const int CharacterLimit = 105;
+
private readonly User user;
private readonly Contact contact;
@@ -92,15 +93,18 @@ public async void OnAppearing()
{
this.GetMessagesAsync(this.Messages);
}
-
- var messagestart = new StartLongRunningTaskMessage();
- MessagingCenter.Send(messagestart, "StopLongRunningTaskMessage");
}
- public void OnDisappearing()
+ public void MessageRestriction(Entry entry)
{
- var messagestart = new StartLongRunningTaskMessage();
- MessagingCenter.Send(messagestart, "StartLongRunningTaskMessage");
+ var val = entry.Text;
+
+ if (val?.Length > CharacterLimit)
+ {
+ val = val.Remove(val.Length - 1);
+ entry.Text = val;
+ this.DisplayMessageTooLong();
+ }
}
private async Task GetContactPublicKey()
@@ -119,8 +123,7 @@ private async Task SendMessage()
{
this.IsBusy = true;
- // No json object, because of the 106 character limit
- if (this.OutGoingText.Length > 105)
+ if (this.OutGoingText.Length > CharacterLimit)
{
this.DisplayMessageTooLong();
}
@@ -140,6 +143,7 @@ private async Task SendMessage()
var tryteUser = new TryteString(encryptedForUser.ToTrytes() + ChiotaIdentifier.FirstBreak + signature + ChiotaIdentifier.SecondBreak + trytesDate + ChiotaIdentifier.End);
await this.SendParallelAsync(tryteContact, tryteUser);
+ await this.AddNewMessagesAsync(this.Messages);
}
this.IsBusy = false;
diff --git a/Chiota/Chiota/ViewModels/ContactListViewModel.cs b/Chiota/Chiota/ViewModels/ContactListViewModel.cs
index 6ca2aef..d5e1aac 100644
--- a/Chiota/Chiota/ViewModels/ContactListViewModel.cs
+++ b/Chiota/Chiota/ViewModels/ContactListViewModel.cs
@@ -3,6 +3,7 @@
using System.Threading.Tasks;
using System.Windows.Input;
+ using Chiota.IOTAServices;
using Chiota.Models;
using Xamarin.Forms;
@@ -43,7 +44,8 @@ private async void OnDecline()
};
// store as rejected on approved contact adress
- await this.user.TangleMessenger.SendJsonMessageAsync(new SentDataWrapper { Data = contact, Sender = this.user.Name }, this.user.ApprovedAddress);
+ var sentData = new SentDataWrapper { Data = contact, Sender = this.user.Name };
+ await this.user.TangleMessenger.SendMessageAsync(IotaHelper.ObjectToTryteString(sentData), this.user.ApprovedAddress);
this.viewCellObject.RefreshContacts = true;
this.isClicked = false;
}
@@ -77,7 +79,8 @@ private async void OnAccept()
private Task SendParallelAsync(Contact contact)
{
// store as approved on own adress
- var firstTransaction = this.user.TangleMessenger.SendJsonMessageAsync(new SentDataWrapper { Data = contact, Sender = this.user.Name }, this.user.ApprovedAddress);
+ var sentData = new SentDataWrapper { Data = contact, Sender = this.user.Name };
+ var firstTransaction = this.user.TangleMessenger.SendMessageAsync(IotaHelper.ObjectToTryteString(sentData), this.user.ApprovedAddress);
contact.Name = this.user.Name;
contact.ImageUrl = this.user.ImageUrl;
@@ -85,7 +88,8 @@ private Task SendParallelAsync(Contact contact)
contact.PublicKeyAdress = this.user.PublicKeyAddress;
// store on other users approved contact address
- var secondTransaction = this.user.TangleMessenger.SendJsonMessageAsync(new SentDataWrapper { Data = contact, Sender = this.user.Name }, this.ContactAdress);
+ sentData = new SentDataWrapper { Data = contact, Sender = this.user.Name };
+ var secondTransaction = this.user.TangleMessenger.SendMessageAsync(IotaHelper.ObjectToTryteString(sentData), this.ContactAdress);
return Task.WhenAll(firstTransaction, secondTransaction);
}
}
diff --git a/Chiota/Chiota/ViewModels/ContactViewModel.cs b/Chiota/Chiota/ViewModels/ContactViewModel.cs
index e09d2bf..50a2cd4 100644
--- a/Chiota/Chiota/ViewModels/ContactViewModel.cs
+++ b/Chiota/Chiota/ViewModels/ContactViewModel.cs
@@ -90,9 +90,9 @@ private async Task> GetConctacts(stri
// right now people can add themselfs to your contacts list, when they know your public key adress and approved contact adress
// in future store approved contacts with MAM
- var contactRequestList = await this.user.TangleMessenger.GetJsonMessageAsync>(this.user.RequestAddress);
+ var contactRequestList = await this.user.TangleMessenger.GetJsonMessageAsync>(this.user.RequestAddress, 3);
- var contactApprovedList = await this.user.TangleMessenger.GetJsonMessageAsync>(this.user.ApprovedAddress);
+ var contactApprovedList = await this.user.TangleMessenger.GetJsonMessageAsync>(this.user.ApprovedAddress, 3);
var contactsWithoutResponse = contactRequestList.Except(contactApprovedList, new ChatAdressComparer()).ToList();
diff --git a/Chiota/Chiota/Views/ChatPage.xaml b/Chiota/Chiota/Views/ChatPage.xaml
index 8dcd225..9407975 100644
--- a/Chiota/Chiota/Views/ChatPage.xaml
+++ b/Chiota/Chiota/Views/ChatPage.xaml
@@ -36,19 +36,20 @@
-
diff --git a/Chiota/Chiota/Views/ChatPage.xaml.cs b/Chiota/Chiota/Views/ChatPage.xaml.cs
index b95a6ff..377d9e5 100644
--- a/Chiota/Chiota/Views/ChatPage.xaml.cs
+++ b/Chiota/Chiota/Views/ChatPage.xaml.cs
@@ -25,6 +25,7 @@ public ChatPage(Contact contact, User user)
}
this.Title = contact.Name;
+ (this.MessageEntry as Entry).TextChanged += this.OnTextChanged;
this.vm = new ChatViewModel(MessagesListView, contact, user) { Navigation = this.Navigation };
this.vm.DisplayMessageTooLong += () => this.DisplayAlert("Error", "Sorry, only 105 characters per message are allowed!", "OK");
this.vm.DisplayInvalidPublicKeyPrompt += () => this.DisplayAlert("Error", "Invalid public key! You contact needs to give you a new contact address.", "OK");
@@ -39,12 +40,19 @@ protected override void OnAppearing()
protected override void OnDisappearing()
{
- this.vm.OnDisappearing();
this.vm.PageIsShown = false;
this.vm = null;
this.Navigation.PopAsync();
}
+ private void OnTextChanged(object sender, EventArgs e)
+ {
+ if (sender is Entry entry)
+ {
+ (this.BindingContext as ChatViewModel)?.MessageRestriction(entry);
+ }
+ }
+
private void Handle_Completed(object sender, EventArgs e)
{
(this.BindingContext as ChatViewModel)?.SendCommand.Execute(null);
diff --git a/README.md b/README.md
index b41324b..4bd5685 100644
--- a/README.md
+++ b/README.md
@@ -35,11 +35,12 @@ Currently, there are the following points on my to-do list:
- [x] Qr codes for address sharing
- [x] Performance improvements
- [x] Check for unique Address public key combination
-- [ ] Improve Notifications/Background Tasks (Android 8.0, Sound, Windows, etc.)
+- [x] Notifications
+- [ ] Chatbot integration
- [ ] Recovery after snapshot
- [ ] Mam Integration
- [ ] Improve/check NTRU solution or switch to SIDH (key only 564 bytes) for key exchange
-- [ ] iOS App
+- [ ] Windows/iOS App
- [ ] Unit testing
- [ ] Code refactoring
diff --git a/UWPRuntimeComponent/BackgroundTask.cs b/UWPRuntimeComponent/BackgroundTask.cs
index f1b7d77..50dc4bd 100644
--- a/UWPRuntimeComponent/BackgroundTask.cs
+++ b/UWPRuntimeComponent/BackgroundTask.cs
@@ -6,21 +6,11 @@ public sealed class BackgroundTask : IBackgroundTask
{
private BackgroundTaskDeferral deferral;
- public void Run(IBackgroundTaskInstance taskInstance)
+ public async void Run(IBackgroundTaskInstance taskInstance)
{
this.deferral = taskInstance.GetDeferral();
// Run your background task code here
- try
- {
- var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
-
- settings.Values.Add("BackgroundTask", "Hello from UWP");
- }
- catch
- {
- // ignored
- }
this.deferral.Complete();
}