A2UI আর্কিটেকচারে, প্রতিটি সারফেস একটি কম্পোনেন্ট ক্যাটালগ দ্বারা চালিত হয়। কোনো এআই এজেন্টকে তার নিজস্ব UI প্রিমিটিভ উদ্ভাবন করতে বা যথেচ্ছ কোড তৈরি করতে দেওয়ার পরিবর্তে, আপনার ক্যাটালগটি এজেন্টের জন্য উপলব্ধ কম্পোনেন্ট, প্রপার্টি স্কিমা এবং ক্যাপাবিলিটিগুলো ঘোষণা করে। এরপর এজেন্ট এই কম্পোনেন্টগুলো ব্যবহার করে একটি ইউজার ইন্টারফেস তৈরি করে।
যখন আপনি আপনার অ্যাপের ডিজাইন সিস্টেমের জন্য একটি কাস্টম ক্যাটালগ তৈরি করেন , তখন আপনি এমন কম্পোনেন্টগুলো ইমপ্লিমেন্ট করেন যা সেই ক্যাটালগ ডেফিনিশনগুলোকে সুনির্দিষ্ট Jetpack Compose UI এলিমেন্টে ম্যাপ করে। প্রতিটি A2UI কম্পোনেন্ট ( A2uiComponent ) তার প্রপার্টি স্কিমা কন্ট্রাক্ট সংজ্ঞায়িত করে, ডাইনামিক ডেটা আসার সাথে সাথে প্রস্তুতি মূল্যায়ন করে, ডেটা মডেল থেকে রিঅ্যাক্টিভ প্রপার্টিগুলো বাইন্ড করে, Compose UI এমিট করে এবং ব্যবহারকারীর ইন্টারঅ্যাকশন অ্যাকশনগুলো এজেন্টের কাছে ডিসপ্যাচ করে।
কম্পোজ UI রেন্ডারার ( androidx.a2ui.compose:compose-ui ) আপনার অ্যাপের ডিজাইন সিস্টেম অনুসরণ করে কাস্টম কম্পোনেন্ট বাস্তবায়নের জন্য প্রয়োজনীয় ইন্টারফেস এবং রিসিভার স্কোপ সরবরাহ করে।
স্ট্যাটিক্যালি টাইপড কম্পোনেন্ট প্রোপার্টি ঘোষণা করুন
রেন্ডার করার আগে, একটি কম্পোনেন্ট এজেন্টের কাছ থেকে যে প্রোপার্টিগুলো প্রত্যাশা করে, সেগুলো ডিক্লেয়ার করুন। রানটাইম লেয়ারটি স্ট্যাটিক্যালি টাইপড A2uiProperty API প্রদান করে, যা JSON স্কিমা তৈরি এবং রানটাইমে ভ্যালু এক্সট্র্যাক্ট করা—উভয় কাজেই ব্যবহৃত হয়:
// Define static properties, dynamic bindings, and component references
val textProp = A2uiProperty.dynamicString("text", required = true)
val variantProp = A2uiProperty.stringEnum("variant", enumValues = listOf("body", "title"))
val childProp = A2uiProperty.componentId("child", required = true)
val actionProp = A2uiProperty.action("action", required = true)
A2uiComponent ইন্টারফেসটি বাস্তবায়ন করুন
একটি কম্পোনেন্টের স্কিমা নির্ধারণ করতে এবং এজেন্ট থেকে প্রাপ্ত প্রোপার্টিগুলোকে কম্পোজ UI-তে ম্যাপ করতে A2uiComponent ইন্টারফেসটি ইমপ্লিমেন্ট করুন:
object CustomTextComponent : A2uiComponent {
private val textProp = A2uiProperty.dynamicString("text", required = true)
private val variantProp = A2uiProperty.stringEnum(
"variant",
enumValues = listOf("body", "title"),
)
override val name = "Text"
override val description = "Displays dynamic text."
override val properties = listOf(textProp, variantProp)
@Composable
override fun A2uiComponentScope.isReady(properties: A2uiComponentProperties): Boolean {
// The component does not become ready until dynamic text data arrives
return properties.bind(textProp) != null
}
@Composable
override fun A2uiComponentScope.Content(
properties: A2uiComponentProperties,
modifier: Modifier,
) {
// Reactively resolve dynamic data binding and subscribe to updates
val text = properties.bind(textProp) ?: ""
// Read the static configuration property
val variant = properties[variantProp] ?: "body"
val textStyle = if (variant == "title") {
MaterialTheme.typography.titleLarge
} else {
MaterialTheme.typography.bodyLarge
}
Text(
text = text,
style = textStyle,
modifier = modifier,
)
}
}
নিয়মিত এবং দ্বিমুখী ডেটা মডেল বাইন্ডিং সমাধান করুন
কম্পোনেন্ট ইমপ্লিমেন্টেশনগুলো ডাইনামিকভাবে বাইন্ড করা প্রোপার্টিগুলো রিজলভ করতে A2uiComponentScope ব্যবহার করে। সাধারণ ডাইনামিক প্রোপার্টিগুলোর ক্ষেত্রে, bind বর্তমান মানটি রিটার্ন করে এবং ডেটা মডেল আপডেটের জন্য স্বয়ংক্রিয়ভাবে সাবস্ক্রাইব করে।
ইন্টারেক্টিভ ইনপুট কম্পোনেন্টগুলোর জন্য, bindUpdater একটি স্টেবল আপডেটার ল্যাম্বডা রিটার্ন করে। যদি এজেন্ট একটি রাইটেবল ডেটা পাথের পরিবর্তে একটি লিটারেল স্ট্রিং প্রদান করে, তাহলে আপডেটার ল্যাম্বডাটি null হয়, যা নির্দেশ করে যে ফিল্ডটি রিড-অনলি।
val labelProp = A2uiProperty.dynamicString("label", required = true)
val valueProp = A2uiProperty.dynamicBoolean("value")
@Composable
fun A2uiComponentScope.CustomCheckbox(properties: A2uiComponentProperties) {
// Read a dynamic property from the data model subscribing to updates
val label = properties.bind(labelProp) ?: ""
// Bind a property value and its updater to handle two-way data binding
val checked = properties.bind(valueProp) ?: false
val onCheckedChange = properties.bindUpdater(valueProp)
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
checked = checked,
onCheckedChange = onCheckedChange,
enabled = (onCheckedChange != null), // Read-only if no writable path was bound
)
Text(text = label)
}
}
ব্যবহারকারীর কার্যকলাপ এজেন্টের কাছে প্রেরণ করুন
ইন্টারেক্টিভ কম্পোনেন্টগুলো ব্যবহারকারীর ইভেন্টগুলো এজেন্টের কাছে ফেরত পাঠাতে A2uiComponentScope.dispatchAction ব্যবহার করে:
object CustomButtonComponent : A2uiComponent {
private val childProp = A2uiProperty.componentId("child", required = true)
private val actionProp = A2uiProperty.action("action", required = true)
override val name = "Button"
override val description = "A clickable button."
override val properties = listOf(childProp, actionProp)
@Composable
override fun A2uiComponentScope.Content(
properties: A2uiComponentProperties,
modifier: Modifier,
) {
val actionDefinition = properties[actionProp]
val childId = properties[childProp] ?: return
val currentAction by rememberUpdatedState(actionDefinition)
val onClick: () -> Unit = remember {
{ currentAction?.let { dispatchAction(it) } }
}
Button(onClick = onClick, modifier = modifier) {
val childState = observeA2uiComponentState(id = childId)
when (childState) {
is A2uiComponentState.Loading -> CircularProgressIndicator()
is A2uiComponentState.Error -> Text("Error")
is A2uiComponentState.Success -> A2uiComponent(childState.component)
}
}
}
}
চাইল্ড কম্পোনেন্ট এবং প্রগ্রেসিভ রেন্ডারিং পরিচালনা করুন
যেসব কম্পোনেন্ট নেস্টেড চাইল্ড সমর্থন করে, তারা চাইল্ডের স্টেট পর্যবেক্ষণ করতে observeA2uiComponentState(id) ব্যবহার করে। এটি প্রগ্রেসিভ রেন্ডারিং সক্ষম করে, যেখানে একটি প্যারেন্ট কন্টেইনার তার শেল রেন্ডার করার সময় চাইল্ড কম্পোনেন্টগুলো স্বাধীনভাবে লোড হয়:
val headerChildProp = A2uiProperty.componentId("headerId", required = true)
@Composable
fun A2uiComponentScope.CustomCompositeContent(
properties: A2uiComponentProperties,
) {
val headerId = properties[headerChildProp] ?: return
val headerState = observeA2uiComponentState(id = headerId)
when (headerState) {
is A2uiComponentState.Loading -> {
// Render a localized loading placeholder
LinearProgressIndicator()
}
is A2uiComponentState.Error -> {
// Render a localized error fallback
Text("Failed to load header")
}
is A2uiComponentState.Success -> {
// Forward the resolved child component to the visual UI router
A2uiComponent(headerState.component)
}
}
}
চাইল্ড আইটেমগুলোর (যেমন কোনো কলাম, সারি বা তালিকার আইটেম) কালেকশন বা তালিকা পরিচালনা করতে, A2uiProperty.childList ব্যবহার করে একটি প্রপার্টি ডিক্লেয়ার করুন এবং bindChildReferences দিয়ে চাইল্ড আইটেমগুলোকে রিজলভ করুন:
val childrenProp = A2uiProperty.childList("children", required = true)
@Composable
fun A2uiComponentScope.CustomColumn(
properties: A2uiComponentProperties,
modifier: Modifier = Modifier,
) {
// Resolve child references (supports both static ID arrays and dynamic data templates)
val childReferences = properties.bindChildReferences(childrenProp) ?: return
Column(modifier = modifier) {
childReferences.forEach { reference ->
key(reference.id, reference.baseDataPath) {
val childState = observeA2uiComponentState(reference)
when (childState) {
is A2uiComponentState.Loading -> CircularProgressIndicator()
is A2uiComponentState.Error -> Text("Failed to load child")
is A2uiComponentState.Success -> A2uiComponent(childState.component)
}
}
}
}
}
বেসিক ক্যাটালগে নেটিভ মিডিয়া রেন্ডারিং একীভূত করুন
প্রদত্ত বেসিক ক্যাটালগ ইমপ্লিমেন্টেশন ( androidx.compose.material3:material3-a2ui ) ব্যবহার করার সময়, আপনি আপনার পছন্দের মিডিয়া লাইব্রেরিগুলো (যেমন ছবির জন্য Coil বা ভিডিওর জন্য ExoPlayer) বেসিক ক্যাটালগের মিডিয়া কম্পোনেন্টগুলোতে যুক্ত করতে পারেন:
// Configure an Image component for the Basic Catalog using Coil
val coilImage = MaterialA2uiBasicCatalogV1Defaults.image { url, desc, scale, modifier, onError ->
AsyncImage(
model = url,
contentDescription = desc,
contentScale = scale,
modifier = modifier,
onError = { state -> onError(state.result.throwable) },
)
}
বাস্তবায়নের বিবরণ
নিম্নলিখিত বিভাগগুলিতে রিকার্সিভ UI এমিশন, ডাইনামিক প্রপার্টি ইভ্যালুয়েশন এবং এরর রিপোর্টিং ব্যাখ্যা করা হয়েছে।
কম্পোনেন্ট ইমপ্লিমেন্টেশন ইউজার জার্নিগুলো নিম্নলিখিত মূল API-গুলো উপস্থাপন করে:
-
A2uiComponent: এমন একটি ইন্টারফেস যা কম্পোনেন্টের মেটাডেটা, প্রপার্টি স্কিমা, প্রস্তুতি যাচাই (isReady) এবং রেন্ডারিং নির্গমন (Content) নির্ধারণ করে। -
A2uiProperty: একটি স্ট্যাটিক্যালি টাইপড প্রপার্টি ডিক্লারেশন যা JSON স্কিমা তৈরি এবং রানটাইম ভ্যালু রেজোলিউশনের জন্য ব্যবহৃত হয়। -
A2uiComponentScope: একটি রিসিভার স্কোপ যা কম্পোনেন্ট ইমপ্লিমেন্টেশনগুলোকে প্রাসঙ্গিক ক্ষমতা (যেমন ডেটা বাইন্ডিং, অ্যাকশন ডিসপ্যাচিং, এবং চাইল্ড স্টেট অবজারভেশন) প্রদান করে। -
A2uiComponentProperties: এজেন্ট থেকে প্রাপ্ত কম্পোনেন্ট প্রোপার্টিগুলোর জন্য একটি কন্টেইনার যা টাইপ-সেফ প্রোপার্টি অ্যাক্সেস প্রদান করে। -
A2uiComponentState: কোনো কম্পোনেন্টের রিঅ্যাক্টিভ লোডিং, সফলতা, বা ত্রুটি সমাধানের অবস্থা নির্দেশ করে।
পুনরাবৃত্তিমূলক UI নির্গমন এবং গতিশীল রাউটিং
কলার দ্বারা হোইস্ট করা রুট স্টেট (অথবা প্যারেন্টের মধ্যে রিজলভ করা চাইল্ড কম্পোনেন্ট স্টেট) A2uiComponent কম্পোজেবল ফাংশনের মাধ্যমে রিকার্সিভ কম্পোনেন্ট রেন্ডারিং শুরু করে। রিজলভ করা স্টেটকে কোনো নির্দিষ্ট UI ইমপ্লিমেন্টেশনের সাথে দৃঢ়ভাবে সংযুক্ত না করে, এই ফাংশনটি একটি ডাইনামিক রাউটার হিসেবে কাজ করে।