XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

STHApplication

【MAUI】寄当家——安卓端交易管理系统

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text.Json;
using JiDangJia.Contracts;
using JiDangJia.Services;

namespace JiDangJia.Views;

public sealed class CommunityCapturePage : ContentPage
{
    private readonly string kind,account=AuthClient.Current.AccountId;
    private readonly Func<CommunityMedia,Task> send;
    private readonly CommunityWebView web=new();
    private readonly Label state=Ui.Text("准备录制",13,Ui.Muted);
    private readonly MemoryStream data=new();
    private readonly Button publish;
    private string uploadId=Guid.NewGuid().ToString("N");
    private CommunityMedia? uploaded;
    private DateTimeOffset? createdAt;
    private bool receiving,complete,busy,visible,paused,sent;
    private bool CanUse=>visible&&!paused&&!AuthClient.Current.Locked&&account==AuthClient.Current.AccountId;
    private Window? window;
    public static async Task<bool> PermissionsFor(string kind)
    {
        if(await Permissions.RequestAsync<Permissions.Microphone>()!=PermissionStatus.Granted)throw new InvalidOperationException("录制语音和视频需要麦克风权限");
        if(kind=="VIDEO"&&await Permissions.RequestAsync<Permissions.Camera>()!=PermissionStatus.Granted)throw new InvalidOperationException("视频功能需要相机权限");return true;
    }
    public static async Task Open(ContentPage page,string kind,Func<CommunityMedia,Task> send){await PermissionsFor(kind);await page.Navigation.PushAsync(new CommunityCapturePage(kind,send));}
    private CommunityCapturePage(string kind,Func<CommunityMedia,Task> send)
    {
        this.kind=kind;this.send=send;Title=kind=="VIDEO"?"录制视频 · 最长30秒":"录制语音 · 最长60秒";publish=Ui.Button("发送录制内容",Publish);publish.IsEnabled=false;
        var grid=CommunityUi.Layout(Ui.Stack(Ui.Text(kind=="VIDEO"?"在 APP 内录制视频":"在 APP 内录制语音",21,bold:true),state),web,Ui.Stack(publish,Ui.Button("取消录制",()=>Navigation.PopAsync(),false)));Content=grid;web.MessageReceived+=Message;
    }
    protected override async void OnAppearing()
    {
        base.OnAppearing();visible=true;paused=false;window=Window;if(window is not null){window.Stopped+=Stopped;window.Resumed+=Resumed;}await Prepare();
    }
    private async Task Prepare(){try{using var stream=await FileSystem.OpenAppPackageFileAsync("community/capture.html");using var reader=new StreamReader(stream);var html=(await reader.ReadToEndAsync()).Replace("__KIND__",kind);if(CanUse)web.Html=html;}catch(Exception ex){if(CanUse)state.Text=ex.Message;}}
    private void Message(string value)
    {
        if(!CanUse||value=="ready")return;try
        {
            using var doc=JsonDocument.Parse(value);var r=doc.RootElement;switch(r.GetProperty("type").GetString())
            {
                case "status":state.Text=r.GetProperty("message").GetString();break;
                case "reset":if(!busy){receiving=complete=false;uploaded=null;data.SetLength(0);uploadId=Guid.NewGuid().ToString("N");publish.IsEnabled=false;}break;
                case "recorded":createdAt=r.TryGetProperty("createdAt",out var stamp)?stamp.GetDateTimeOffset():DateTimeOffset.Now;publish.IsEnabled=true;state.Text="录制完成,可以预览后发送。";break;
                case "start":data.SetLength(0);receiving=true;complete=false;break;
                case "chunk":if(!receiving)return;var bytes=Convert.FromBase64String(r.GetProperty("data").GetString()!);if(data.Length+bytes.Length>25*1024*1024){receiving=false;throw new ArgumentException("录制文件过大,请重新录制");}data.Write(bytes);break;
                case "complete":receiving=false;complete=true;_=UploadAndSend();break;
            }
        }
        catch(Exception ex)when(ex is JsonException or FormatException or ArgumentException){state.Text=ex.Message;publish.IsEnabled=true;}
    }
    private async Task Publish(){if(busy||!CanUse)return;await web.Run("window.setSending(true);");if(uploaded is not null||complete)await UploadAndSend();else{publish.IsEnabled=false;await web.Run("window.exportRecording();");}}
    private async Task UploadAndSend()
    {
        if(busy||!CanUse)return;busy=true;publish.IsEnabled=false;
        try{state.Text="正在发送录制内容…";uploaded??=await AuthClient.Current.UploadMedia(data.ToArray(),kind,uploadId,"CAMERA",createdAt,true);if(!CanUse)return;await send(uploaded);sent=true;if(CanUse&&Navigation.NavigationStack.LastOrDefault()==this)await Navigation.PopAsync();}
        catch(Exception ex){if(visible){state.Text=ex.Message;publish.IsEnabled=true;await web.Run("window.setSending(false);");}}
        finally{busy=false;if(CanUse&&!sent&&complete)publish.IsEnabled=true;}
    }
    private void Stopped(object? sender,EventArgs e){paused=true;web.Stop();state.Text="已暂停录制,请返回前台后重新录制。";publish.IsEnabled=false;receiving=false;if(!busy&&!complete)data.SetLength(0);}
    private async void Resumed(object? sender,EventArgs e){paused=false;if(!CanUse)return;if(sent){if(Navigation.NavigationStack.LastOrDefault()==this)await Navigation.PopAsync();return;}await Prepare();publish.IsEnabled=!busy&&complete;state.Text=complete?"已保留录制内容,可以继续发送。":"请重新录制。";}
    protected override void OnDisappearing(){visible=false;if(window is not null){window.Stopped-=Stopped;window.Resumed-=Resumed;}web.Stop();data.Dispose();base.OnDisappearing();}
}