228 lines
9.0 KiB
C#
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>();
|
|
} |