simplenotesdroid/MainActivity.cs

228 lines
9.0 KiB
C#

using System.Net.Http.Json;
using System.Text.Json.Serialization;
using Android.Content;
using Android.Runtime;
using Android.Views;
using AndroidX.AppCompat.App;
using AndroidX.RecyclerView.Widget;
using AndroidX.SwipeRefreshLayout.Widget;
using Google.Android.Material.Color;
using Google.Android.Material.FloatingActionButton;
using Google.Android.Material.Snackbar;
using Google.Android.Material.TextField;
namespace SimpleNotes;
[Activity(Label = "@string/app_name", MainLauncher = true,Theme ="@style/Theme.SimpleNotes")]
public class MainActivity : AppCompatActivity
{
public static (string Endpoint,string Username,string Password) GetPrefs(Context ctx)
{
var config=ctx.GetSharedPreferences("config",Android.Content.FileCreationMode.Private);
if(config != null)
{
var endpoint = config.GetString("endpoint","") ?? "";
var username = config.GetString("username","") ?? "";
var password = config.GetString("password","") ?? "";
return (endpoint.TrimEnd('/'),username,password);
}
return ("","","");
}
public static readonly HttpClient Client =new HttpClient();
public override bool OnCreateOptionsMenu(IMenu? menu)
{
MenuInflater.Inflate(Resource.Menu.menu_main,menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
int id=item.ItemId;
if(id == Resource.Id.action_settings)
{
var intent = new Intent(this,typeof(SettingActivity));
StartActivityForResult(intent,0);
}
return base.OnOptionsItemSelected(item);
}
Func<Task>? fItems;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
DynamicColors.ApplyToActivityIfAvailable(this);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
SetSupportActionBar(FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.toolbar));
FloatingActionButton? fab = FindViewById<FloatingActionButton>(Resource.Id.fab);
SwipeRefreshLayout? swipeRefreshLayout = FindViewById<SwipeRefreshLayout>(Resource.Id.swiperefresh);
RecyclerView? recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
if(fab == null || swipeRefreshLayout == null || recyclerView == null) return;
recyclerView.SetLayoutManager(new LinearLayoutManager(this));
recyclerView.SetAdapter(new NoteAdapter(new List<Note>()));
fab.Click += (sender,e)=>{
var intent = new Intent(this,typeof(NoteActivity));
StartActivityForResult(intent,0);
};
SemaphoreSlim slim=new SemaphoreSlim(1,1);
fItems = FetchItems;
async Task FetchItems()
{
await slim.WaitAsync();
Console.WriteLine("ready to fetch");
var (endpoint,username,password) = GetPrefs(this);
if(!string.IsNullOrWhiteSpace(endpoint) && !string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
{
var request = new HttpRequestMessage(HttpMethod.Get,$"{endpoint}/api/note");
request.Headers.Add("Authorization",$"Basic {Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{username}:{password}"))}");
var response=await MainActivity.Client.SendAsync(request);
if(response.IsSuccessStatusCode)
{
Console.WriteLine("Success status code");
var notes = await response.Content.ReadFromJsonAsync<_NotesResponse>();
Console.WriteLine($"{notes == null} {notes?.Success ?? false}");
if(notes != null && notes.Success)
{
this.RunOnUiThread(()=>{
var adapter = new NoteAdapter(notes.Notes);
adapter.LaunchNote += LaunchNote;
adapter.DeleteNote += DeleteNote;
recyclerView.SetAdapter(adapter);
});
void LaunchNote(object? sender,long e)
{
Intent intent=new Intent(this,typeof(NoteActivity));
intent.PutExtra("note_id",e);
StartActivityForResult(intent,0);
}
void DeleteNote(object? sender,long e){
var alert=new AndroidX.AppCompat.App.AlertDialog.Builder(this);
alert.SetTitle("Delete Note?");
alert.SetPositiveButton("Yes",async(sender2,e2)=>{
var request = new HttpRequestMessage(HttpMethod.Delete,$"{endpoint}/api/note?id={e}");
request.Headers.Add("Authorization",$"Basic {Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{username}:{password}"))}");
var response=await MainActivity.Client.SendAsync(request);
if(response.IsSuccessStatusCode)
{
var data = await response.Content.ReadFromJsonAsync<_SuccessResp>();
if(data == null || !data.Success) return;
Note? sen = sender as Note;
if(sen != null)
notes.Notes.Remove(sen);
this.RunOnUiThread(()=>{
var adapter2 = new NoteAdapter(notes.Notes);
adapter2.DeleteNote += DeleteNote;
adapter2.LaunchNote += LaunchNote;
recyclerView.SetAdapter(adapter2);
});
}
});
alert.SetNegativeButton("No",(sender2,e2)=>{});
alert.Create().Show();
}
}
}
}
slim.Release();
}
swipeRefreshLayout.Refresh += async(sender,e)=>{
await FetchItems();
this.RunOnUiThread(()=>{
swipeRefreshLayout.Refreshing=false;
});
};
Task.Run(FetchItems).Wait(0);
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent? data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(fItems != null)
Task.Run(fItems).Wait(0);
}
}
internal class NoteAdapter : RecyclerView.Adapter
{
private Note[] notes;
public event EventHandler<long>? LaunchNote;
public event EventHandler<long>? DeleteNote;
public NoteAdapter(List<Note> notes)
{
this.notes = notes.ToArray();
}
public void InvokeDeleteNote(Note n,long note)
{
DeleteNote?.Invoke(n,note);
}
public void InvokeLaunchNode(Note n,long note)
{
LaunchNote?.Invoke(n,note);
}
public override int ItemCount => notes.Length;
public class NoteViewHolder : RecyclerView.ViewHolder
{
public Note Item {set {
item = value;
if(tv != null)
{
tv.Text = item.Title;
}
}}
ImageButton? imageButton;
TextView? tv;
Note item=new Note();
public NoteViewHolder(View itemView,NoteAdapter adapter) : base(itemView)
{
tv=itemView.FindViewById<TextView>(Resource.Id.rvtextView);
imageButton = itemView.FindViewById<ImageButton>(Resource.Id.rvimagebutton);
if(imageButton != null)
{
imageButton.Click += (sender,e)=>{
adapter.InvokeDeleteNote(this.item,this.item.Id);
};
}
itemView.Click += (sender,e)=>{
adapter.InvokeLaunchNode(this.item,this.item.Id);
};
}
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
var noteHolder=holder as NoteViewHolder;
if(noteHolder != null)
{
noteHolder.Item = notes[position];
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View? itemView = LayoutInflater.From(parent.Context)?.Inflate(Resource.Layout.note_view, parent, false);
if(itemView == null) throw new Exception();
return new NoteViewHolder(itemView,this);
}
}
public class _SuccessResp
{
[JsonPropertyName("success")]
public bool Success {get;set;}
}
public class _NotesResponse
{
[JsonPropertyName("success")]
public bool Success {get;set;}
[JsonPropertyName("notes")]
public List<Note> Notes {get;set;}=new List<Note>();
}