waterui_cli/android/
backend.rs1use std::path::{Path, PathBuf};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 backend::Backend,
7 templates::{self, TemplateContext},
8};
9
10#[derive(Debug, Serialize, Deserialize, Clone)]
14pub struct AndroidBackend {
15 #[serde(
16 default = "default_android_project_path",
17 skip_serializing_if = "is_default_android_project_path"
18 )]
19 project_path: PathBuf,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 version: Option<String>,
22}
23
24impl AndroidBackend {
25 #[must_use]
27 pub fn new() -> Self {
28 Self {
29 project_path: default_android_project_path(),
30 version: None,
31 }
32 }
33
34 #[must_use]
36 pub fn with_project_path(mut self, path: impl Into<PathBuf>) -> Self {
37 self.project_path = path.into();
38 self
39 }
40
41 #[must_use]
43 pub const fn project_path(&self) -> &PathBuf {
44 &self.project_path
45 }
46
47 #[must_use]
49 pub fn gradlew_path(&self) -> PathBuf {
50 let base = &self.project_path;
51 if cfg!(windows) {
52 base.join("gradlew.bat")
53 } else {
54 base.join("gradlew")
55 }
56 }
57}
58
59impl Default for AndroidBackend {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl Backend for AndroidBackend {
66 const DEFAULT_PATH: &'static str = "android";
67
68 fn path(&self) -> &Path {
69 &self.project_path
70 }
71
72 async fn init(
73 project: &crate::project::Project,
74 ) -> Result<Self, crate::backend::FailToInitBackend> {
75 let manifest = project.manifest();
76
77 let app_name = manifest
79 .package
80 .name
81 .chars()
82 .filter(|c| c.is_alphanumeric())
83 .collect::<String>();
84
85 let backend_relative_path = project.backend_relative_path::<Self>();
87
88 let android_backend_path = manifest
91 .waterui_path
92 .as_ref()
93 .map(|p| PathBuf::from(p).join("backends/android"));
94
95 let project_path = default_android_project_path();
96
97 let android_permissions: Vec<String> = manifest
99 .permissions
100 .iter()
101 .filter(|(_, entry)| entry.is_enabled())
102 .map(|(name, _)| name.clone())
103 .collect();
104
105 let ctx = TemplateContext {
106 app_display_name: manifest.package.name.clone(),
107 app_name,
108 crate_name: project.crate_name().to_string(),
109 bundle_identifier: manifest.package.bundle_identifier.clone(),
110 author: String::new(),
111 android_backend_path,
112 use_remote_dev_backend: manifest.waterui_path.is_none(),
113 waterui_path: manifest.waterui_path.as_ref().map(PathBuf::from),
114 backend_project_path: Some(backend_relative_path),
115 android_permissions,
116 };
117
118 templates::android::scaffold(&project.backend_path::<Self>(), &ctx)
119 .await
120 .map_err(crate::backend::FailToInitBackend::Io)?;
121
122 Ok(Self {
123 project_path,
124 version: None,
125 })
126 }
127}
128
129fn default_android_project_path() -> PathBuf {
130 PathBuf::from("android")
131}
132
133fn is_default_android_project_path(s: &Path) -> bool {
134 s == Path::new("android")
135}