diff --git a/.gitignore b/.gitignore
index 104b544..e4b72b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@
##
## Get latest from `dotnet new gitignore`
+appsettings.json
+
# dotenv files
.env
diff --git a/App.xaml.cs b/App.xaml.cs
index 8239297..839c851 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -1,29 +1,15 @@
-using menu.Data;
-using menu.ViewModels;
-
-namespace menu
+namespace menu
{
public partial class App : Application
{
public App()
{
InitializeComponent();
-
MainPage = new AppShell();
}
protected override void OnStart()
{
- CheckDeadlinesAsync();
- }
-
- private async void CheckDeadlinesAsync()
- {
- var database = new MenuDatabase();
-
- var viewModel = new MainViewModel(database);
-
- await viewModel.CheckDeadlinesAsync();
}
protected override void OnSleep()
diff --git a/AppShell.xaml b/AppShell.xaml
index 51f648b..8a3d72f 100644
--- a/AppShell.xaml
+++ b/AppShell.xaml
@@ -11,4 +11,8 @@
Title="List"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
+
diff --git a/Data/AzureFunctionService.cs b/Data/AzureFunctionService.cs
new file mode 100644
index 0000000..6937a8a
--- /dev/null
+++ b/Data/AzureFunctionService.cs
@@ -0,0 +1,97 @@
+using Microsoft.Extensions.Configuration;
+
+namespace menu.Data
+{
+ public class AzureFunctionService
+ {
+ private readonly HttpClient httpClient;
+ private readonly IConfiguration configuration;
+
+ public AzureFunctionService(HttpClient httpClient, IConfiguration configuration)
+ {
+ this.httpClient = httpClient;
+ this.configuration = configuration;
+ }
+
+ public async Task ShareListAzure(string shareCode, string senderID, string listID, string listData)
+ {
+ string shareListUrl = $"https://anonylistfunctions.azurewebsites.net/api/ShareList?shareCode={shareCode}&senderID={senderID}&listID={listID}&listData={listData}";
+ string functionKey = configuration["SHARE_LIST_KEY"];
+
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, shareListUrl);
+ request.Headers.Add("x-functions-key", functionKey);
+
+ var response = await httpClient.SendAsync(request);
+
+ if (response.IsSuccessStatusCode)
+ {
+ return await response.Content.ReadAsStringAsync();
+ }
+ else
+ {
+ throw new Exception("Error sharing list");
+ }
+ }
+
+ public async Task ReceiveSharedListAzure(string shareCode, string senderID)
+ {
+ string receiveSharedListUrl = $"https://anonylistfunctions.azurewebsites.net/api/ReceiveSharedList?shareCode={shareCode}&senderID={senderID}";
+ string functionKey = configuration["RECEIVE_SHARED_LIST_KEY"];
+
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, receiveSharedListUrl);
+ request.Headers.Add("x-functions-key", functionKey);
+
+ var response = await httpClient.SendAsync(request);
+
+ if (response.IsSuccessStatusCode)
+ {
+ return await response.Content.ReadAsStringAsync();
+ }
+ else
+ {
+ throw new Exception("Error receiving shared list");
+ }
+ }
+
+ public async Task CheckQueueAzure(string userID)
+ {
+ string checkQueueUrl = $"https://anonylistfunctions.azurewebsites.net/api/CheckQueue?userID={userID}";
+ string functionKey = configuration["CHECK_QUEUE_KEY"];
+
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, checkQueueUrl);
+ request.Headers.Add("x-functions-key", functionKey);
+
+ var response = await httpClient.SendAsync(request);
+
+ if (response.IsSuccessStatusCode)
+ {
+ return await response.Content.ReadAsStringAsync();
+ }
+ else
+ {
+ throw new Exception("Error checking the queue for list updates");
+ }
+ }
+
+ public async Task UpdateListAzure(string senderID, string listID, string recipientIDList, string listData)
+ {
+ string updateListUrl = $"https://anonylistfunctions.azurewebsites.net/api/UpdateList?senderID={senderID}&listID={listID}&recipientIDList={recipientIDList}&listData={listData}";
+ string functionKey = configuration["UPDATE_LIST_KEY"];
+
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, updateListUrl);
+ request.Headers.Add("x-functions-key", functionKey);
+
+ var response = await httpClient.SendAsync(request);
+
+ if (response.IsSuccessStatusCode)
+ {
+ return await response.Content.ReadAsStringAsync();
+ }
+ else
+ {
+ throw new Exception("Error updating the list " + listID);
+ }
+
+ }
+ }
+}
diff --git a/Data/MenuDatabase.cs b/Data/MenuDatabase.cs
index 947cf2e..c916fbf 100644
--- a/Data/MenuDatabase.cs
+++ b/Data/MenuDatabase.cs
@@ -5,41 +5,75 @@ namespace menu.Data
{
public class MenuDatabase
{
- private SQLiteConnection db;
+ private readonly SQLiteConnection db;
- private static string DatabasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "menu.db");
+ private static readonly string DatabasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "menu.db");
public MenuDatabase()
{
db = new SQLiteConnection(DatabasePath);
db.CreateTable();
db.CreateTable();
+ db.CreateTable();
+ }
+
+ public User GetDefaultUser()
+ {
+ return db.Query("SELECT * FROM user WHERE id = 0").FirstOrDefault();
}
public List GetUserLists()
{
- List lists = db.Query("SELECT * FROM user_lists");
+ List lists;
+
+ lists = db.Query("SELECT * FROM user_lists WHERE is_in_trash = 0");
if (lists == null || lists.Count == 0)
{
+ db.Insert(defaultUser);
+
db.Insert(defaultUserList);
db.Insert(changeTitleItem);
db.Insert(addListItemItem);
db.Insert(addListItem);
db.Insert(deleteListItemItem);
- lists = db.Query("SELECT * FROM user_lists");
+
+ lists = db.Query("SELECT * FROM user_lists WHERE is_in_trash = 0");
}
return lists;
}
+ public List GetTrashUserLists()
+ {
+ List trashLists;
+
+ trashLists = db.Query("SELECT * FROM user_lists WHERE is_in_trash = 1");
+
+ if (trashLists == null || trashLists.Count == 0)
+ {
+ db.Insert(defaultUser);
+
+ db.Insert(defaultUserList);
+
+ db.Insert(changeTitleItem);
+ db.Insert(addListItemItem);
+ db.Insert(addListItem);
+ db.Insert(deleteListItemItem);
+
+ trashLists = db.Query("SELECT * FROM user_lists WHERE is_in_trash = 1");
+ }
+
+ return trashLists;
+ }
+
public int SaveUserList(UserList list)
{
if (list.Id != 0)
{
db.Update(list);
- return list.Id;
+ return list.Id;
}
else
{
@@ -49,27 +83,41 @@ public int SaveUserList(UserList list)
}
}
- public UserList DeleteUserList(UserList list)
+ public void MoveToTrash(UserList list)
{
- int result = db.Delete(list);
- if (result == 0)
+ if (list.Id == 1)
{
- return null;
- } else if (result == 1)
- {
- return list;
- } else
+ db.Update(list);
+ }
+ if (list.Id != 1)
{
- throw new Exception(string.Format("Error occurred trying to delete UserList {0}", list));
+ list.IsInTrash = true;
+ db.Update(list);
}
}
+ public void RestoreFromTrash(UserList list)
+ {
+ list.IsInTrash = false;
+ db.Update(list);
+ }
+
+ public void DeleteUserListPermanently()
+ {
+ db.Execute("DELETE FROM user_lists WHERE is_in_trash = 1");
+ }
+
public List GetListItemsByListId(int id)
{
return db.Table().Where(li => li.UserListId == id).ToList();
}
+ public List GetTrashLists()
+ {
+ return db.Table().Where(li => li.IsInTrash == true).ToList();
+ }
+
public ListItem GetListItemById(int id)
{
return db.Table().Where(li => li.Id == id).FirstOrDefault();
@@ -80,7 +128,8 @@ public int SaveListItem(ListItem li)
if (li.Id != 0)
{
return db.Update(li);
- } else
+ }
+ else
{
return db.Insert(li);
}
@@ -92,15 +141,23 @@ public ListItem DeleteListItem(ListItem li)
if (result == 0)
{
return null;
- } else if (result == 1)
+ }
+ else if (result == 1)
{
return li;
- } else
+ }
+ else
{
throw new Exception(string.Format("Error occurred trying to delete ListItem {0}", li));
}
}
+ private readonly User defaultUser = new()
+ {
+ Id = 0,
+ Uuid = Guid.NewGuid().ToString()
+ };
+
private readonly UserList defaultUserList = new()
{
Name = "Welcome",
diff --git a/Data/SharingService.cs b/Data/SharingService.cs
new file mode 100644
index 0000000..b9c1f6d
--- /dev/null
+++ b/Data/SharingService.cs
@@ -0,0 +1,121 @@
+using menu.Models;
+using Newtonsoft.Json;
+
+namespace menu.Data
+{
+ public class SharingService
+ {
+ private readonly AzureFunctionService azureFunctionService;
+
+ public SharingService(AzureFunctionService azureFunctionService)
+ {
+ this.azureFunctionService = azureFunctionService;
+ }
+
+ public async Task ShareList(User user, string shareCode, UserList list)
+ {
+ try
+ {
+ var result = await azureFunctionService.ShareListAzure(shareCode, user.Uuid, list.UserUuid, list.ToAzureString());
+ if (result != null)
+ {
+ return true;
+ }
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ return false;
+ }
+ }
+
+ public async Task ReceiveSharedList(string userId, string shareCode)
+ {
+ try
+ {
+ var result = await azureFunctionService.ReceiveSharedListAzure(shareCode, userId);
+ if (result != null)
+ {
+ return JsonConvert.DeserializeObject(result);
+ }
+ return null;
+ }
+ catch (Exception ex)
+ {
+ if (ex is JsonSerializationException)
+ {
+ Console.WriteLine("Failure to deserialize the result: " + ex.Message);
+ return null;
+ }
+ else
+ {
+ Console.WriteLine(ex.Message);
+ return null;
+ }
+ }
+ }
+
+ public async Task CheckQueue(string userId)
+ {
+ try
+ {
+ var result = await azureFunctionService.CheckQueueAzure(userId);
+ if (result != null)
+ {
+ return JsonConvert.DeserializeObject(result);
+ }
+ return null;
+ }
+ catch (Exception ex)
+ {
+ if (ex is JsonSerializationException)
+ {
+ Console.WriteLine("Failure to deserialize the result: " + ex.Message);
+ return null;
+ }
+ else
+ {
+ Console.WriteLine(ex.Message);
+ return null;
+ }
+ }
+ }
+
+ public async Task UpdateList(string senderId, UserList list, string recipientIdList)
+ {
+ try
+ {
+ var result = await azureFunctionService.UpdateListAzure(senderId, list.UserUuid, recipientIdList, list.ToAzureString());
+ if (result != null)
+ {
+ return true;
+ }
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ return false;
+ }
+ }
+
+ public async Task UpdateList(string senderId, UserList list, List recipientIdList)
+ {
+ try
+ {
+ var result = await azureFunctionService.UpdateListAzure(senderId, list.UserUuid, string.Join(",", recipientIdList), list.ToAzureString());
+ if (result != null)
+ {
+ return true;
+ }
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ return false;
+ }
+ }
+ }
+}
diff --git a/MainPage.xaml b/MainPage.xaml
index 947c9f9..fbd3e8a 100644
--- a/MainPage.xaml
+++ b/MainPage.xaml
@@ -13,9 +13,11 @@
FontAttributes="Bold"
FontSize="Large"
Text="View Lists" />
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
+
+
-
-
+
+
+
+
diff --git a/MainPage.xaml.cs b/MainPage.xaml.cs
index 974421b..362625f 100644
--- a/MainPage.xaml.cs
+++ b/MainPage.xaml.cs
@@ -4,13 +4,38 @@ namespace menu
{
public partial class MainPage : ContentPage
{
+
public MainPage(MainViewModel vm)
{
InitializeComponent();
BindingContext = vm;
- UserListCollectionView.SelectionChanged += vm.OnListCollectionSelectionChanged;
+ UserListCollectionView.SelectionChanged += vm.OnListCollectionSelectionChanged;
+ }
+
+ protected override async void OnAppearing()
+ {
+ base.OnAppearing();
+ var viewModel = BindingContext as MainViewModel;
+ await viewModel.CheckDeadlinesAsync();
}
+ private async void OnNavigateButtonClicked(object sender, EventArgs e)
+ {
+ var viewModel = BindingContext as MainViewModel;
+ var share = new Share(viewModel);
+
+ await Shell.Current.Navigation.PushAsync(share);
+ }
+
+ private async void OnNavigateButtonClicked1(object sender, EventArgs e)
+ {
+ var viewModel = BindingContext as MainViewModel;
+ var bin = new RecycleBin(viewModel);
+
+ await Shell.Current.Navigation.PushAsync(bin);
+ }
+
+
}
}
diff --git a/MauiProgram.cs b/MauiProgram.cs
index d4346db..a208250 100644
--- a/MauiProgram.cs
+++ b/MauiProgram.cs
@@ -1,5 +1,6 @@
using menu.Data;
using menu.ViewModels;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace menu
@@ -17,12 +18,17 @@ public static MauiApp CreateMauiApp()
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
+ builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
+
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
#if DEBUG
- builder.Logging.AddDebug();
+ builder.Logging.AddDebug();
#endif
return builder.Build();
diff --git a/Models/AzureList.cs b/Models/AzureList.cs
new file mode 100644
index 0000000..d6ac194
--- /dev/null
+++ b/Models/AzureList.cs
@@ -0,0 +1,9 @@
+namespace menu.Models
+{
+ public class AzureList
+ {
+ public string ListId { get; set; }
+ public string ListData { get; set; }
+ public string OriginalSenderId { get; set; }
+ }
+}
diff --git a/Models/AzureListData.cs b/Models/AzureListData.cs
new file mode 100644
index 0000000..f84abb2
--- /dev/null
+++ b/Models/AzureListData.cs
@@ -0,0 +1,14 @@
+namespace menu.Models
+{
+ public class AzureListData
+ {
+ public string Name { get; set; }
+ public List AzureListItems { get; set; }
+
+ public AzureListData(string name, List azureListItems)
+ {
+ Name = name;
+ AzureListItems = azureListItems;
+ }
+ }
+}
diff --git a/Models/AzureListItem.cs b/Models/AzureListItem.cs
new file mode 100644
index 0000000..5d83673
--- /dev/null
+++ b/Models/AzureListItem.cs
@@ -0,0 +1,8 @@
+namespace menu.Models
+{
+ public class AzureListItem
+ {
+ public string Text { get; set; }
+ public bool IsComplete { get; set; }
+ }
+}
diff --git a/Models/AzureListUpdates.cs b/Models/AzureListUpdates.cs
new file mode 100644
index 0000000..b3c8848
--- /dev/null
+++ b/Models/AzureListUpdates.cs
@@ -0,0 +1,7 @@
+namespace menu.Models
+{
+ public class AzureListUpdates
+ {
+ public List listUpdates;
+ }
+}
diff --git a/Models/ListItem.cs b/Models/ListItem.cs
index 7a675d7..0a69c25 100644
--- a/Models/ListItem.cs
+++ b/Models/ListItem.cs
@@ -16,5 +16,14 @@ public class ListItem
public string Text { get; set; }
[Column("is_complete")]
public bool IsComplete { get; set; }
+
+ public AzureListItem ToAzureListItem()
+ {
+ return new AzureListItem
+ {
+ Text = this.Text,
+ IsComplete = this.IsComplete
+ };
+ }
}
}
diff --git a/Models/User.cs b/Models/User.cs
new file mode 100644
index 0000000..c4508b9
--- /dev/null
+++ b/Models/User.cs
@@ -0,0 +1,18 @@
+using SQLite;
+
+namespace menu.Models
+{
+ [Table("user")]
+ public class User
+ {
+ [PrimaryKey, AutoIncrement]
+ [Column("ID")]
+ public int Id { get; set; }
+
+ [Column("UUID")]
+ public string Uuid { get; set; }
+
+ [Ignore]
+ public List UserLists { get; set; }
+ }
+}
diff --git a/Models/UserList.cs b/Models/UserList.cs
index f777a3b..15705d0 100644
--- a/Models/UserList.cs
+++ b/Models/UserList.cs
@@ -1,9 +1,11 @@
-using SQLite;
+using CommunityToolkit.Mvvm.ComponentModel; //新
+using Newtonsoft.Json;
+using SQLite;
namespace menu.Models
{
[Table("user_lists")]
- public class UserList
+ public class UserList : ObservableObject //新
{
[PrimaryKey, AutoIncrement]
[Column("id")]
@@ -13,7 +15,23 @@ public class UserList
public string Name { get; set; }
[Column("deadline")]
public DateTime Deadline { get; set; }
+ [MaxLength(50)]
+ [Column("share_code")]
+ public string ShareCode { get; set; }
+
+ [Column("is_in_trash")]
+ public bool IsInTrash { get; set; } = false;
+ [Column("user_uuid")]
+ public string UserUuid { get; set; }
[Ignore]
-public List ListItems { get; set; }
+ public List ListItems { get; set; }
+
+ public string ToAzureString()
+ {
+ AzureListData azureListData = new(this.Name, this.ListItems.Select(item => item.ToAzureListItem()).ToList());
+
+ return JsonConvert.SerializeObject(azureListData).ToString();
+ }
+
}
}
diff --git a/Platforms/Android/MainActivity.cs b/Platforms/Android/MainActivity.cs
index 5c80f2a..831237a 100644
--- a/Platforms/Android/MainActivity.cs
+++ b/Platforms/Android/MainActivity.cs
@@ -1,6 +1,5 @@
using Android.App;
using Android.Content.PM;
-using Android.OS;
namespace menu
{
diff --git a/Platforms/MacCatalyst/Program.cs b/Platforms/MacCatalyst/Program.cs
index 3bb1964..40f7261 100644
--- a/Platforms/MacCatalyst/Program.cs
+++ b/Platforms/MacCatalyst/Program.cs
@@ -1,5 +1,4 @@
-using ObjCRuntime;
-using UIKit;
+using UIKit;
namespace menu
{
diff --git a/Platforms/Windows/App.xaml.cs b/Platforms/Windows/App.xaml.cs
index 4baf22a..201db12 100644
--- a/Platforms/Windows/App.xaml.cs
+++ b/Platforms/Windows/App.xaml.cs
@@ -1,6 +1,4 @@
-using Microsoft.UI.Xaml;
-
-// 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.
namespace menu.WinUI
diff --git a/RecycleBin.xaml b/RecycleBin.xaml
new file mode 100644
index 0000000..caaf7aa
--- /dev/null
+++ b/RecycleBin.xaml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RecycleBin.xaml.cs b/RecycleBin.xaml.cs
new file mode 100644
index 0000000..24f56d8
--- /dev/null
+++ b/RecycleBin.xaml.cs
@@ -0,0 +1,43 @@
+using menu.ViewModels;
+
+namespace menu
+{
+ public partial class RecycleBin : ContentPage
+ {
+
+ public RecycleBin(MainViewModel vm)
+ {
+ InitializeComponent();
+ BindingContext = vm;
+ }
+
+ private void RecoveredClicked(object sender, EventArgs e)
+ {
+
+
+ }
+
+ private async void DeletedClicked(object sender, EventArgs e)
+ {
+ bool answer = await DisplayAlert("Confirm Delete", "Are you sure you want to completely delete these items?", "Yes", "No");
+ if (answer)
+ {
+
+ }
+ else
+ {
+
+ }
+ }
+
+ private async void returnMainForBin(object sender, EventArgs e)
+ {
+ await Navigation.PopToRootAsync();
+ return;
+
+ //MenuDatabase database = new MenuDatabase();
+ //MainViewModel viewModel = new MainViewModel(database);
+ //await Navigation.PushAsync(new MainPage(viewModel));
+ }
+ }
+}
diff --git a/Resources/Images/background2.svg b/Resources/Images/background2.svg
new file mode 100644
index 0000000..26cf34a
--- /dev/null
+++ b/Resources/Images/background2.svg
@@ -0,0 +1,9938 @@
+
+
diff --git a/Share.xaml b/Share.xaml
new file mode 100644
index 0000000..a29070e
--- /dev/null
+++ b/Share.xaml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Share.xaml.cs b/Share.xaml.cs
new file mode 100644
index 0000000..4df7846
--- /dev/null
+++ b/Share.xaml.cs
@@ -0,0 +1,57 @@
+using menu.ViewModels;
+
+namespace menu;
+
+public partial class Share : ContentPage
+{
+ public Share(MainViewModel vm)
+ {
+ InitializeComponent();
+ BindingContext = vm;
+ }
+
+ private int _shareCount = 1;
+
+
+ private void DecreaseCount(object sender, EventArgs e)
+ {
+ if (_shareCount > 1)
+ {
+ _shareCount--;
+ ShareCountEntry.Text = _shareCount.ToString();
+ }
+ }
+
+ private void IncreaseCount(object sender, EventArgs e)
+ {
+ _shareCount++;
+ ShareCountEntry.Text = _shareCount.ToString();
+ }
+
+ private void CanViewClicked(object sender, EventArgs e)
+ {
+
+ }
+
+ private void CanEditClicked(object sender, EventArgs e)
+ {
+
+ }
+
+ private void CopyClicked(object sender, EventArgs e)
+ {
+ var textToCopy = codeGen.Text;
+
+ Clipboard.SetTextAsync(textToCopy);
+ }
+
+ private async void ReturnMainForShare(object sender, EventArgs e)
+ {
+ await Navigation.PopToRootAsync();
+ return;
+
+ //MenuDatabase database = new MenuDatabase();
+ //MainViewModel viewModel = new MainViewModel(database);
+ //await Navigation.PushAsync(new MainPage(viewModel));
+ }
+}
\ No newline at end of file
diff --git a/ShareCenter.xaml b/ShareCenter.xaml
new file mode 100644
index 0000000..f6efecb
--- /dev/null
+++ b/ShareCenter.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ShareCenter.xaml.cs b/ShareCenter.xaml.cs
new file mode 100644
index 0000000..717b15d
--- /dev/null
+++ b/ShareCenter.xaml.cs
@@ -0,0 +1,44 @@
+namespace menu;
+
+public partial class ShareCenter : ContentPage
+{
+ public ShareCenter()
+ {
+ InitializeComponent();
+ }
+
+ private async void PasteCode(object sender, EventArgs e)
+ {
+ if (Clipboard.HasText)
+ {
+ var text = await Clipboard.GetTextAsync();
+
+ paste.Text = text;
+ }
+ else
+ {
+ await Microsoft.Maui.Controls.Application.Current.MainPage.DisplayAlert("Message", "No code has been added.", "OK");
+ }
+ }
+
+ private async void CancelReq(object sender, EventArgs e)
+ {
+ paste.Text = "";
+
+ await Shell.Current.GoToAsync("//MainPage"); ;
+ }
+
+ private async void ConfirmReq(object sender, EventArgs e)
+ {
+ if (!string.IsNullOrEmpty(paste.Text))
+ {
+
+
+ await Shell.Current.GoToAsync("//MainPage");
+ }
+ else
+ {
+ await Microsoft.Maui.Controls.Application.Current.MainPage.DisplayAlert("Message", "No code has been added.", "OK");
+ }
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/MainViewModel.cs b/ViewModels/MainViewModel.cs
index b12af65..a589490 100644
--- a/ViewModels/MainViewModel.cs
+++ b/ViewModels/MainViewModel.cs
@@ -3,29 +3,31 @@
using menu.Data;
using menu.Models;
using System.Collections.ObjectModel;
-using menu;
-using System.ComponentModel;
-using System.Runtime.CompilerServices;
namespace menu.ViewModels
{
public partial class MainViewModel : ObservableObject
{
- MenuDatabase db;
+ public MenuDatabase db;
+ private readonly SharingService sharingService;
- public MainViewModel(MenuDatabase database)
+ public MainViewModel(MenuDatabase database, SharingService sharingService)
{
db = database;
+ this.sharingService = sharingService;
IsVisible = false;
var displayInfo = DeviceDisplay.MainDisplayInfo;
+
ListCollectionHeight = (displayInfo.Height / displayInfo.Density) * .25;
ItemCollectionHeight = (displayInfo.Height / displayInfo.Density) * .5;
ListCollection = new ObservableCollection(db.GetUserLists());
SelectedList = ListCollection.FirstOrDefault();
Items = new ObservableCollection(db.GetListItemsByListId(SelectedList.Id));
-
-
+
+ TrashListCollection = new ObservableCollection(db.GetTrashUserLists());
+ SelectedTrashList = TrashListCollection.FirstOrDefault();
+ TrashUserLists = new ObservableCollection(db.GetTrashLists());
}
[ObservableProperty]
@@ -41,9 +43,18 @@ public MainViewModel(MenuDatabase database)
[ObservableProperty]
ObservableCollection listCollection;
+ [ObservableProperty]
+ ObservableCollection trashListCollection;
+
[ObservableProperty]
ObservableCollection items;
+ [ObservableProperty]
+ ObservableCollection trashUserLists;
+
+ [ObservableProperty]
+ UserList selectedTrashList;
+
[ObservableProperty]
UserList selectedList;
@@ -56,6 +67,15 @@ public MainViewModel(MenuDatabase database)
[ObservableProperty]
DateTime deadline = DateTime.Now.AddDays(7);
+ [ObservableProperty]
+ private string shareCode;
+
+ [ObservableProperty]
+ string sharedCode;
+
+ [ObservableProperty]
+ ObservableCollection selectedTrashItems = new();
+
[RelayCommand]
void ToggleListCollectionVisibility()
{
@@ -108,9 +128,11 @@ void UpdateTitle()
{
list.Name = SelectedList.Name;
list.Deadline = SelectedList.Deadline;
+ list.IsInTrash = SelectedList.IsInTrash;
newListCollection.Add(list);
db.SaveUserList(list);
- } else
+ }
+ else
{
newListCollection.Add(list);
}
@@ -119,6 +141,43 @@ void UpdateTitle()
ListCollection = newListCollection;
}
+ [RelayCommand]
+ void GetShareCode()
+ {
+ ObservableCollection currentListCollection = ListCollection;
+ ObservableCollection newListCollection = new();
+
+ foreach (UserList list in currentListCollection)
+ {
+ list.Name = SelectedList.Name;
+ list.Deadline = SelectedList.Deadline;
+ list.IsInTrash = SelectedList.IsInTrash;
+ list.ShareCode = SelectedList.ShareCode;
+ newListCollection.Add(list);
+ db.SaveUserList(list);
+
+ }
+
+ ListCollection = newListCollection;
+ }
+
+
+
+ [RelayCommand]
+ async Task RetrieveListByShareCode(string code)
+ {
+ var list = db.GetUserLists().FirstOrDefault(l => l.ShareCode == code);
+ if (list == null)
+ {
+ await Shell.Current.DisplayAlert("Error", "Invalid share code.", "OK");
+ return;
+ }
+
+ SelectedList = list;
+ Items = new ObservableCollection(db.GetListItemsByListId(SelectedList.Id));
+ }
+
+
public void OnListCollectionSelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
@@ -128,7 +187,8 @@ public void OnListCollectionSelectionChanged(object sender, SelectionChangedEven
Items = new ObservableCollection(db.GetListItemsByListId(SelectedList.Id));
IsVisible = false;
- } catch (Exception ex)
+ }
+ catch (Exception ex)
{
Console.WriteLine(ex.Message);
SelectedList = ListCollection.FirstOrDefault();
@@ -148,6 +208,7 @@ void AddList()
Name = "New List " + (ListCollection.Count + 1),
ListItems = new List(),
Deadline = Deadline,
+ IsInTrash = false,
};
ListCollection.Add(newList);
@@ -166,6 +227,80 @@ void SaveList()
}
+
+ [RelayCommand]
+ void RecoverSelectedLists(UserList li)
+ {
+ if (li != null)
+ {
+ db.RestoreFromTrash(li);
+ RefreshTrashList();
+ }
+ }
+
+ [RelayCommand]
+ void SaveShareCode(UserList li)
+ {
+ li = SelectedList;
+ if (li != null)
+ {
+ var random = new Random();
+ string code;
+ bool isUnique;
+
+ do
+ {
+ code = new string(Enumerable.Repeat("abcdefghijklmnopqrstuvwxyz0123456789", 10)
+ .Select(s => s[random.Next(s.Length)]).ToArray());
+
+ isUnique = !db.GetUserLists().Any(l => l.ShareCode == code);
+ } while (!isUnique);
+
+ li.ShareCode = code;
+ db.SaveUserList(li);
+ }
+ }
+
+
+ [RelayCommand]
+ void DeleteSelectedListsForever()
+ {
+ db.DeleteUserListPermanently();
+ RefreshTrashList();
+ }
+
+
+ public void RefreshTrashList()
+ {
+ TrashUserLists = new ObservableCollection(db.GetTrashUserLists());
+ }
+
+ [RelayCommand]
+
+ async Task DeleteList()
+ {
+ if (Items == null) return;
+
+ bool isConfirmed = await Shell.Current.DisplayAlert(
+ "Confirm Delete",
+ $"Are you sure you want to delete '{SelectedList.Name}'?",
+ "Yes", "No");
+
+ if (isConfirmed)
+ {
+ db.MoveToTrash(SelectedList);
+ ListCollection.Remove(SelectedList);
+
+ var welcomeList = ListCollection.FirstOrDefault(l => l.Name == "Welcome") ?? ListCollection.FirstOrDefault();
+ if (welcomeList != null)
+ {
+ SelectedList = welcomeList;
+ Items = new ObservableCollection(db.GetListItemsByListId(SelectedList.Id));
+ }
+ }
+ db.SaveUserList(SelectedList);
+ }
+
public async Task CheckDeadlinesAsync()
{
var listsWithTodaysDeadline = GetListsWithTodaysDeadline();
@@ -181,5 +316,28 @@ public List GetListsWithTodaysDeadline()
return ListCollection.Where(list => list.Deadline.Date == today).ToList();
}
+ [RelayCommand]
+ public async Task GenerateShareCode()
+ {
+ var random = new Random();
+ string code;
+ bool isUnique;
+
+ do
+ {
+ code = new string(Enumerable.Repeat("abcdefghijklmopqrstuvwxyz0123456789", 10)
+ .Select(s => s[random.Next(s.Length)]).ToArray());
+
+ isUnique = !db.GetUserLists().Any(l => l.ShareCode == code);
+ } while (!isUnique);
+
+ SelectedList.ShareCode = code;
+ db.SaveUserList(SelectedList); // 确保更新数据库中的列表
+
+ User self = db.GetDefaultUser();
+ await sharingService.ShareList(self, code, SelectedList);
+ }
+
+
}
}
diff --git a/ViewModels/ShareCenterViewModel.cs b/ViewModels/ShareCenterViewModel.cs
new file mode 100644
index 0000000..e2c9f4b
--- /dev/null
+++ b/ViewModels/ShareCenterViewModel.cs
@@ -0,0 +1,94 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using menu.Data;
+using menu.Models;
+using Newtonsoft.Json;
+
+namespace menu.ViewModels
+{
+ public partial class ShareCenterViewModel : ObservableObject
+ {
+ private readonly MenuDatabase db;
+ private readonly SharingService sharingService;
+
+ public ShareCenterViewModel(MenuDatabase db, SharingService sharingService)
+ {
+ this.db = db;
+ this.sharingService = sharingService;
+ }
+
+ [ObservableProperty]
+ string shareCode;
+
+ [RelayCommand]
+ void ReceiveSharedList()
+ {
+ User user = db.GetDefaultUser();
+
+ var result = sharingService.ReceiveSharedList(user.Uuid, ShareCode);
+
+ if (result.IsCompletedSuccessfully)
+ {
+ UserList newList = ProcessAzureData(result.Result);
+ }
+
+
+ }
+
+ private UserList ProcessAzureData(AzureList azureList)
+ {
+ try
+ {
+ AzureListData listData = JsonConvert.DeserializeObject(azureList.ListData);
+ string listName = listData.Name;
+ List listItems = listData.AzureListItems;
+
+ UserList newList = new()
+ {
+ Name = listName,
+ UserUuid = azureList.OriginalSenderId,
+ IsInTrash = false,
+ ShareCode = ShareCode,
+ ListItems = new List()
+ };
+
+ int newListId = db.SaveUserList(newList);
+ List outListItems = ProcessAzureListItems(newListId, listItems);
+
+ newList.ListItems = outListItems;
+ return newList;
+ }
+ catch (Exception ex)
+ {
+ if (ex is JsonSerializationException)
+ {
+ Console.WriteLine("Failure to deserialize the Azure List Data: " + ex.Message);
+ }
+ else
+ {
+ Console.WriteLine(ex.Message);
+ }
+ return null;
+ }
+ }
+
+ private List ProcessAzureListItems(int dbListId, List azureListItems)
+ {
+ List listItems = new();
+ foreach (AzureListItem ali in azureListItems)
+ {
+ ListItem li = new()
+ {
+ Text = ali.Text,
+ IsComplete = ali.IsComplete,
+ UserListId = dbListId
+ };
+
+ int liId = db.SaveListItem(li);
+ listItems.Add(db.GetListItemById(liId));
+ }
+
+ return listItems;
+ }
+ }
+}
diff --git a/menu.csproj b/menu.csproj
index 59a49ad..bc6b258 100644
--- a/menu.csproj
+++ b/menu.csproj
@@ -50,10 +50,25 @@
+
+
+
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+