From 41c484eaf83fe8b9a4a326345f506a4350a458b8 Mon Sep 17 00:00:00 2001 From: lincube Date: Sun, 26 Jul 2026 22:28:25 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20Android=20?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=20head=20=E4=B8=8E=E5=85=B1?= =?UTF-8?q?=E4=BA=AB=E7=A7=BB=E5=8A=A8=E5=A3=B3=EF=BC=88=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Directory.Packages.props | 1 + .../LanMountainDesktop.Mobile.Android.csproj | 23 +++++++ .../MainActivity.cs | 19 ++++++ .../MobileAndroidApplication.cs | 26 ++++++++ .../Resources/drawable/icon.png | Bin 0 -> 13761 bytes .../Resources/values/styles.xml | 8 +++ .../LanMountainDesktop.Mobile.csproj | 23 +++++++ LanMountainDesktop.Mobile/MobileApp.axaml | 8 +++ LanMountainDesktop.Mobile/MobileApp.axaml.cs | 33 ++++++++++ .../ViewModels/WidgetPanelViewModel.cs | 57 ++++++++++++++++++ .../Views/WidgetPanelView.axaml | 44 ++++++++++++++ .../Views/WidgetPanelView.axaml.cs | 11 ++++ 12 files changed, 253 insertions(+) create mode 100644 LanMountainDesktop.Mobile.Android/LanMountainDesktop.Mobile.Android.csproj create mode 100644 LanMountainDesktop.Mobile.Android/MainActivity.cs create mode 100644 LanMountainDesktop.Mobile.Android/MobileAndroidApplication.cs create mode 100644 LanMountainDesktop.Mobile.Android/Resources/drawable/icon.png create mode 100644 LanMountainDesktop.Mobile.Android/Resources/values/styles.xml create mode 100644 LanMountainDesktop.Mobile/LanMountainDesktop.Mobile.csproj create mode 100644 LanMountainDesktop.Mobile/MobileApp.axaml create mode 100644 LanMountainDesktop.Mobile/MobileApp.axaml.cs create mode 100644 LanMountainDesktop.Mobile/ViewModels/WidgetPanelViewModel.cs create mode 100644 LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml create mode 100644 LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index b5802d1..0521c14 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,6 +4,7 @@ + diff --git a/LanMountainDesktop.Mobile.Android/LanMountainDesktop.Mobile.Android.csproj b/LanMountainDesktop.Mobile.Android/LanMountainDesktop.Mobile.Android.csproj new file mode 100644 index 0000000..0d711c0 --- /dev/null +++ b/LanMountainDesktop.Mobile.Android/LanMountainDesktop.Mobile.Android.csproj @@ -0,0 +1,23 @@ + + + net10.0-android + 24 + Exe + enable + enable + org.lanmountain.desktop + 1 + 0.0.0-dev + apk + true + + + + + + + + + + + diff --git a/LanMountainDesktop.Mobile.Android/MainActivity.cs b/LanMountainDesktop.Mobile.Android/MainActivity.cs new file mode 100644 index 0000000..7167066 --- /dev/null +++ b/LanMountainDesktop.Mobile.Android/MainActivity.cs @@ -0,0 +1,19 @@ +using Android.App; +using Android.Content.PM; +using Avalonia.Android; + +namespace LanMountainDesktop.Mobile.Android; + +/// +/// Android 入口 Activity。承载 MobileApp(单视图组件面板)。 +/// Avalonia 12 起 AppBuilder 定制移至 。 +/// +[Activity( + Label = "阑山桌面", + Theme = "@style/MyTheme.NoActionBar", + Icon = "@drawable/icon", + MainLauncher = true, + ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] +public class MainActivity : AvaloniaMainActivity +{ +} diff --git a/LanMountainDesktop.Mobile.Android/MobileAndroidApplication.cs b/LanMountainDesktop.Mobile.Android/MobileAndroidApplication.cs new file mode 100644 index 0000000..32677ce --- /dev/null +++ b/LanMountainDesktop.Mobile.Android/MobileAndroidApplication.cs @@ -0,0 +1,26 @@ +using Android.App; +using Android.Runtime; +using Avalonia; +using Avalonia.Android; +using LanMountainDesktop.Mobile; + +namespace LanMountainDesktop.Mobile.Android; + +/// +/// Android 应用级入口。Avalonia 12 中 AppBuilder 的创建/定制由 +/// AvaloniaAndroidApplication<TApp> 子类负责(而非 Activity)。 +/// +[Application] +public class MobileAndroidApplication : AvaloniaAndroidApplication +{ + protected MobileAndroidApplication(nint javaReference, JniHandleOwnership transfer) + : base(javaReference, transfer) + { + } + + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .WithInterFont(); + } +} diff --git a/LanMountainDesktop.Mobile.Android/Resources/drawable/icon.png b/LanMountainDesktop.Mobile.Android/Resources/drawable/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c89feab27534bad82618e80ed18419e5c953e8cf GIT binary patch literal 13761 zcmeHu_dnJD8~zc622oMT3aQ8{WRGN&Q8KbC92Jh;$yOASjIxrEnYUGB9lKOyQ%1(2 z>~ZXMj&siUe(C-G{srI1?I(*L_{reG9#&t8rlO@x3S%>VTG}nm!7( z3;w$c#jpo{tUmlfgda3+`WmXJg0>UW@C%)tijE2j^&w*4_U+y9JEOCvi5m*V^cnd_ z^Udj<4GJY`q@|`}@X&I8h;jRcZOykOYdp4y!~WH|XoYk7jr!qf$7fGpxMKH-_p0sL zvy3qU$GX)8y;)6Iqoaid>`(Vc`wD$pc!T%AoVP>!9U)WO$%E}{J~f5CB+2u&*F`A3 z;G>4-)j6nijBoC8ABHA&P;u_=l#m?ZftIG++822uL(v{|Wxeub-T#nwdPcJME-!v&ZvGx4WVSNosMK*_!mst|0S=oXoJSG5^>}Yw zoT!zE+eAwgF;R+{I@ z>Dln_bAAfAE9ecvkc8`)W{zQQY6wlZvx6Q@d8>Xo@vUO_+0=NEs8GA~J zeeab*%j&@wfju5Eb^qO6W=mS1U+%Mxs7TtKZ!e?*c*b=HrQGP$P9c+qj_vl+y#DLs zy;ghS`uM+BG{2|i(z#2k4C(jbzOp|5cbXaUf_llXnqCT4<_G1^3P1Yq<{7oJ!(37h z@rOk%2djEmgZ{hSa`lIbg4e}MPxnu(#iITl4F6i19u1p_`RQJBH=Q)DoozuDA}7)M z+l!`#&_kI9Ir@H}QfZ(I3gVDs!7#cEZBW`%2| zg(phbum5{LYh}wDneJBl_XX7<5`Q-_vhT9hZuzaTm!TJU|J##0i5tV-dS?yZ@l1DR zo-eEq5&!RA^q;TcU71(en_|x;dLB^!Z}JUNg1T=ajjenQ_Z~TGV;RU|{qLfGXn!qf zpK>?1bb|abys11O%)VZMfPy)1vZ0G@l03itO`)#SC?q1g^Y_ ztnnp%M`AWn%F%T}=+Ws;zY1T{gDv80;dpLgO*DjArPB{MtI@El-{Y+Oru~vA$E!PM zy7RdGHhIg})cL+eaAON;&Kl+2wG3vtg9NzXDZ_sZv;aF!mJNI5e!SbcE9Ch^Yhtrw z+0dyZIqZW&)9%)s^SNH@en0;)%zQBatLy#kOZWPVG6&t-6_y+MA{yUaPq+E{{21nz zGlZD*(Ti>q+Rj2R^i~-MV$Ydn-0RMo@Hong%(E*)>rbrU^t3HNQS|d;=XXW9)L2cl zB;0VFY@6ScN5y4XlHOB(nOC@KjedGER22&gbCpb7%QVb2A~5zQI@O#ZZ7eWjzAZIP zcV`drj8n@L9wV8R5yDJfzZk7kL8XvviL28toD8e8y`nQ_w26?3SxwhwevbFsrFg9D z{k>#*tMC17{k)sv#f~huAvtT_CE`+V)j!7Q)&sOW9&mlw85$sqt-o)k2JwojiUg=U zChPtV!KC_pnKvy7=QRpyDPF}oJC84_m)!qp)01a{T$^$okRz0TcF_C#sD$%K-L=VG zQ=swk<0_%8WFxff<3E==5+Llr^I0UFVA?e|V>B1&O{2#MXINpxN zD8APJuHe!~GPGWf{m8jde@=GYb3DeF-@Ydg?R~NiNW@4?vq+`3dIT5eOh3&bLETqK z?9YdyfPn-UL!^zz(k9D$N|Y;nQ!K2d;0BU9?(5O*%r0$m&lJJuHWO;~i1PYef9twh zz|KI3dzJN=_pcnOv!W7>u@9quCNluSp&n+!+Xzp$|3oP5DVyxG8!UH;mU1*LR$u{0 zK`lPxVp{#m;S_}1d#fd09Bp>;)6U>bOYTEPx-n=%zWu}(Xj(|IePOlHu=hgswKCcs ztze`7ZXCc=>L^mT-O4Um9hLE3&)d%>-{)}k?_#R-IM{)clLha%fuyrT2G1mkyM>8bvXn!lV{Yz z<;#(xJ71n%!=eVOy~_qYCzGNj?TsLU0RrFvz${;)TVFQ;z92I*sr9Qi$TezpxY4jP z2-CN!Pcr5OXddkFkc58Y3{J>#= zH&j4SPmQnlhN5DN4^RifhEBi+^*e+`si{zj!9$8ov$*9LbyfMlINW;({Fzkgdp6R|G93GY*Us_ zA_83f5IqPihi-0K?TlWv?Tw7>ry$1qb25Wd!_*idW8IJAe`j`56u2S=Pdy@JL{~Pp z=(;{D}O#Y$N`oa1e!XM$AUvxzl%lg%lJ#o3jBcS$agPGbIia=A8Sv+JDBZ4LSD^i{#VKP5Eg#` z(=@8yOPMY6AM)*hQSV%g_9OXkFMS)YdqfMfu0oiUrT4t#8U2iq{!%)~!KjcESlaqPvtty(t`Ucr0!ZUVJksDdsQNRm#myJ0W`)s-97#Aixy`;7w;niSR zU|x~oI8a&ynQG+035wYv~(zpqXpA3C=xd(7js+ zJs^){*N{X=XPOaQ3cpz_LAR!BECz!qxSx2aTQr`|RtoX<8}$AbQW#qe|gsRHz*b=?!e zvxBeI!;d#T-o5X!8NBq7#=>y5fa9-^uuQhF4h&BqE(sNrzf1q%0YeeOfNA&7_2t@G zk=$;RThIh>g^#u&S8ou* zNqYXomvh6_a^;-CDImj|;AotKY#=r;C4+>4wuSe6$uiKNit3F&EM#90SUP8JzEAD1 z;osT7gq;jx(|8a&V_8+?wRXQ^wxF_QU4RjJxaFf0et5ouyL~^mqWm$Y?JWUh>kQ%) zeZ6vSen?B)WN)APClHqMwWIdQolDt=s9x)HXXGBtF<`!oP69#iDzs8+N>Qrq|H{9U zZ#-}WE9Pwz*b`?tCTZMs`|@~mCT0kSCPnY;;i=`ZCO&DrPq938d!-02Kw{Aa#xx$w zHPMzd;9wSwY-EE$jnCFtvNyqnV=3qZdjLl20wC-eqrCY3WJDyOLMpTqB((aAY;EfT zXo~#E#CQTj`Td_~w?1=Ic#cWfhz&#s?QH59gLjb^9Df-AiRHulZdf=s>sC)?DS3@t zgWzn%D`_EEs*3HmjcfAV7@E|bl=E7>>rB%1glV6W9&`@e@;)WLbKrgySPb}D_pTAo z_?}Cp4dqhs5?flp!{Y(G7C85488-`LG#d-Rf8%VLqQ5xCTazhGCxM<27SaH#Bz%ePGR`9bZxp?0&hgQNN$d9las+f4p|Fji zb>?rdAz>UhVQan|U|7Ar2~1K1*2aaSkN=OFltMw7%b%|psvntD8wtu^?P~=0!k+6r zwTB+CprRiucJ*qk6GJw$5;4&r^P7=8ap;tGWNV@{eOdHfoAzV{3CCX-%EI$S?7Cas zS1l@%^Rk<#^ORDYRwY9ToMNC&`XPxeN?U8BlwP?1qmleP-=BT%B!H0`c1!YE>v3rdA4_~8E4jZMP}~|j2&J3UOj51={|zk z9@0l2jy_=r3UCS&owhc)5vrT~BU`Fxn8xc@D&%E@> z1waF6Cr1i~(v_{pU54Mzxsm;Nz-C!ZuSQPk;Az8uUTtlRh1nNWeAS8np_K?kS^3$7)AZLh;4I4(%gCJYh90&CA5zQHNgZ_JBF5V9+>03~)ydLLnvv2dq7096BDbV}tC*o|axY5o`|Pvyh20a+-3iFib70r1HjP#LAx#9gRkQKJg4*#sz%Usx()`al zw~l(@ez!{FTlPL`0C$kb!0Xj4#OUTk3Qy+{yT_9N-L5e$N2M1!tv-JW5;9gr`8QD2 zgXg`*<`zdkkCPT^nK9fA!Bai;Uav5L`ZsD*a_nR?d|?is~DT9gcw>@9oxT)sSsA$Ugt2mN=6;BBkQ< z0`mts$cV+-&wh{*-mV{0u-1EnthsD6*_MQGWL=i$A`n11Cn5jqf4FlwK@N*?HiJh* zYq#}ZOF4dj8E_XCF7oV^Sm865f|+7y>6z%t=%Te{e2E{cz91*_R;ka_OachddbOsl$jDMQ zzw-X}=Zw3ZY3N#&sg^tXoy2(wFRT3ax~G=Dj@oIj zW=D2wWd4vAsOl?e@K$wqF_p&vEq-rGniR#S@f|G6K*H9_*6%P;n~}Ol`jrnHo08

2q4U{KjPr=;`qbvSP6xQ?K}7zGv2~U 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%0Dq|X{?6Mk~i?8NL81_tZK{l z=ZfGi-FPwHDUne%dKx~B7q5^uD92sSqcHSS>FVLX4N+U!Q$@AVG}EpiP((bS3P(lP z>Fe!D=u~mF+ckx1xPK^MU$z+?axz5rz`8Q4N>zL4SP z|9P~ga7u%Yw$|dyvm>_9k9Fd(+Tf|{2(utD{{AZbH7R+2W<=QU7^v))A7Z3GaD1%v zQ~|UDki>*ciZT)fQx`6JUV$(IaosrAUpyqO9Q~$~le*ej`%~$lF^tjOet7pjHo74} z#ZISlxUvc^wv50i=n`lSVc{FJZmlHXnoB+aE5mHvg7lq<^q8Q94jOtckGUi|KB?Gx zMzMs(6t}|OJ^`_- zn`&?NZd|FMo*Hf1edww|+>ziKnlN2r*N~J)#W}6yxuHtqJAnpDQ!Jbqg z&~t2ycsluDv}~uFC~*@ZjEstcT>TbWcQEH!N)HS0 zd${@)hCMuhT1`xCqw|OCb*#_(4Y12Al@I3mfu^CAlx^a_Xm)HoCDyq17Fej1odkSZ z;zFISE-0)d$m$+gy#Sd$4(x)WVI}eSFOB7MMa`S3Jp3`NPiX2qk#<8UXYV=3r#J?U zK~V_#eQ`pjB}L}sH(~XsA{JelSTD2^FTZVQ7fN~B^%vL_^!a?DCoDMEK=4)Y4dtgu zo@|0!3rsN3&1808gF(wAO$w!%D3x!P!zT zP-oc65B&viO{T-G*vXetPMwJ$EM9aTQP$Ph(FQtLP`z#{?G}G5Lu)hvHOt+XtXH*AiMuaL6LDD@5nOpIdOpB}KNe5x z-tjUQDXOR*OA+N87Y?bQhea! zz0b$}{Xu`f<+j1eFTT`MWW)*cj!j0tqYYSr;qxJAga|$VldNGUl>E#s{mC9!{z|T4 z8?x}o?&A1s?jCiV*uhb$yyE=VYAZb;c5(9ahn%V*W%1wLpe5Ux0jpu z@A9*DPs4*bngPUAABvi!2t1lRsmwH^+&_5r!(S0#XlA&J1oNZ}}cA5cUchRtf+O zraRsS%2`~CtA76`g#S|XJ(RO0v^)Lf?VjYlTbhBpY%O^uBCp2JSh)?=)OB zfoG0>ZK8c#cD4kZK7#q|^>pN{F1OhPBlvb0+)!{@GGRkvyOGd00|Ls5ANR!J1p7x+vnARDjg{DTi+G}laJx2Xqi|Ec!!Z@bX%(RdZ*$MxfdKk8aCjT2Q>qCdr#tdzB1S z=n1Y(_cQjSu#3fi$;gu12R>7OlI**P*44+*;2H1jaV=f_fOPlGl;eYl=@XSEqG0;| z)+1rds=j&MEbi0o@+;5f$*bMU{CE9*pfw=_X`*v^U$eKE=vUOK;t%EZ46wrpk}5!i zhmv=B-S{a(i&J^QMDSp>s7kjI`=~$^xWqh_00y#mVPT2}jv89vg`nNmB%R+=lZL_$ z6;-4XSegNqX)HGvPHzk84oCCE37fEn9QHktM{AOFu$f=X3?x-1q&$R@Q~(`-jt3E> z3Rv-|x`5}I#_Du<+l{X5C@5Sw>j^?dLl|~xyjoEoX}h4rwH@jT|Kcu|>PEjx#q~HCGr*5cgi+5bDs_LV9bxU*9ZuzP+)xi|G5v z0Qs{Jc4cf=x6BbDQF-#fG~LytTkj$!J$^oF9 zhus-k))X$~=SWxH|Ngw>e}6yo|Ld=bs@Axdl^#FN#tQGdr40SND6Px7Y6Ysd9{(TX Ci+>dW literal 0 HcmV?d00001 diff --git a/LanMountainDesktop.Mobile.Android/Resources/values/styles.xml b/LanMountainDesktop.Mobile.Android/Resources/values/styles.xml new file mode 100644 index 0000000..668bb66 --- /dev/null +++ b/LanMountainDesktop.Mobile.Android/Resources/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/LanMountainDesktop.Mobile/LanMountainDesktop.Mobile.csproj b/LanMountainDesktop.Mobile/LanMountainDesktop.Mobile.csproj new file mode 100644 index 0000000..6daa19d --- /dev/null +++ b/LanMountainDesktop.Mobile/LanMountainDesktop.Mobile.csproj @@ -0,0 +1,23 @@ + + + net10.0 + enable + enable + true + + + + + + + + + + + + + + + + + diff --git a/LanMountainDesktop.Mobile/MobileApp.axaml b/LanMountainDesktop.Mobile/MobileApp.axaml new file mode 100644 index 0000000..481d86a --- /dev/null +++ b/LanMountainDesktop.Mobile/MobileApp.axaml @@ -0,0 +1,8 @@ + + + + + diff --git a/LanMountainDesktop.Mobile/MobileApp.axaml.cs b/LanMountainDesktop.Mobile/MobileApp.axaml.cs new file mode 100644 index 0000000..ca5d6bb --- /dev/null +++ b/LanMountainDesktop.Mobile/MobileApp.axaml.cs @@ -0,0 +1,33 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using LanMountainDesktop.Mobile.ViewModels; +using LanMountainDesktop.Mobile.Views; + +namespace LanMountainDesktop.Mobile; + +///

+/// 移动端应用入口。以单视图生命周期承载组件面板。 +/// 与桌面宿主 (LanMountainDesktop.App) 共享契约、外观与组件运行时, +/// 但不包含桌面层、托盘、进程外插件等桌面专属能力。 +/// +public partial class MobileApp : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is ISingleViewApplicationLifetime singleView) + { + singleView.MainView = new WidgetPanelView + { + DataContext = new WidgetPanelViewModel() + }; + } + + base.OnFrameworkInitializationCompleted(); + } +} diff --git a/LanMountainDesktop.Mobile/ViewModels/WidgetPanelViewModel.cs b/LanMountainDesktop.Mobile/ViewModels/WidgetPanelViewModel.cs new file mode 100644 index 0000000..5bc99c0 --- /dev/null +++ b/LanMountainDesktop.Mobile/ViewModels/WidgetPanelViewModel.cs @@ -0,0 +1,57 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace LanMountainDesktop.Mobile.ViewModels; + +/// +/// 组件面板视图模型。 +/// 移动端不提供桌面自由摆放,组件以卡片流形式呈现。 +/// 后续由组件运行时(DesktopComponents.Runtime)通过 +/// 注入真实组件视图。 +/// +public sealed partial class WidgetPanelViewModel : ObservableObject +{ + public ObservableCollection Widgets { get; } = []; + + [ObservableProperty] + private string _title = "组件面板"; + + public WidgetPanelViewModel() + { + // 首版占位卡片:标记组件运行时的接入点。 + Widgets.Add(new WidgetCardViewModel("时间表", "课程表 / 日程组件将在此呈现")); + Widgets.Add(new WidgetCardViewModel("天气", "天气组件将在此呈现")); + Widgets.Add(new WidgetCardViewModel("插件组件", "已安装插件提供的组件将在此呈现")); + } + + /// + /// 组件运行时接入点:注册一个真实组件卡片。 + /// + public void RegisterWidget(WidgetCardViewModel widget) + { + Widgets.Add(widget); + } +} + +/// +/// 单个组件卡片。 为空时显示占位说明文本, +/// 非空时承载组件运行时提供的真实控件。 +/// +public sealed partial class WidgetCardViewModel : ObservableObject +{ + [ObservableProperty] + private string _name; + + [ObservableProperty] + private string _placeholder; + + [ObservableProperty] + private object? _content; + + public WidgetCardViewModel(string name, string placeholder, object? content = null) + { + _name = name; + _placeholder = placeholder; + _content = content; + } +} diff --git a/LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml b/LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml new file mode 100644 index 0000000..47172e0 --- /dev/null +++ b/LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml.cs b/LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml.cs new file mode 100644 index 0000000..5e909a2 --- /dev/null +++ b/LanMountainDesktop.Mobile/Views/WidgetPanelView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace LanMountainDesktop.Mobile.Views; + +public partial class WidgetPanelView : UserControl +{ + public WidgetPanelView() + { + InitializeComponent(); + } +}