XR-এর জন্য Jetpack Compose ব্যবহার করে স্থানিক UI তৈরি করুন
সেভ করা পৃষ্ঠা গুছিয়ে রাখতে 'সংগ্রহ' ব্যবহার করুন
আপনার পছন্দ অনুযায়ী কন্টেন্ট সেভ করুন ও সঠিক বিভাগে রাখুন।
প্রযোজ্য এক্সআর ডিভাইস
এই নির্দেশিকা আপনাকে এই ধরনের এক্সআর ডিভাইসগুলির জন্য অভিজ্ঞতা তৈরি করতে সাহায্য করে।
Jetpack Compose for XR-এর সাহায্যে, আপনি সারি এবং কলামের মতো পরিচিত Compose ধারণাগুলি ব্যবহার করে ডিক্লারেটিভভাবে আপনার স্পেশিয়াল UI এবং লেআউট তৈরি করতে পারেন। এটি আপনাকে আপনার বিদ্যমান অ্যান্ড্রয়েড UI-কে 3D স্পেসে প্রসারিত করতে অথবা সম্পূর্ণ নতুন ইমারসিভ 3D অ্যাপ্লিকেশন তৈরি করতে সাহায্য করে।
আপনি যদি বিদ্যমান কোনো অ্যান্ড্রয়েড ভিউ-ভিত্তিক অ্যাপকে স্পেশিয়ালাইজ করতে চান, তবে আপনার কাছে বেশ কয়েকটি ডেভেলপমেন্ট বিকল্প রয়েছে। আপনি ইন্টারঅপারেবিলিটি এপিআই ব্যবহার করতে পারেন, কম্পোজ এবং ভিউ একসাথে ব্যবহার করতে পারেন, অথবা সরাসরি সিনকোর (SceneCore) লাইব্রেরির সাথে কাজ করতে পারেন। আরও বিস্তারিত জানতে ভিউ নিয়ে কাজ করার বিষয়ে আমাদের নির্দেশিকাটি দেখুন।
কোডল্যাব
অ্যান্ড্রয়েড এক্সআর-এর মূল বিষয়গুলো জানুন: পর্ব ১ - মোড এবং স্পেশিয়াল প্যানেল
arrow_forward
উপস্থান এবং স্থানিক উপাদান সম্পর্কে
অ্যান্ড্রয়েড এক্সআর (Android XR)-এর জন্য অ্যাপ লেখার সময় সাবস্পেস (subspace ) এবং স্পেশিয়ালাইজড কম্পোনেন্ট (spatialized components) -এর ধারণাগুলো বোঝা গুরুত্বপূর্ণ।
সাবস্পেস সম্পর্কে
Android XR-এর জন্য ডেভেলপ করার সময়, আপনাকে আপনার অ্যাপ বা লেআউটে একটি সাবস্পেস যোগ করতে হবে। সাবস্পেস হলো আপনার অ্যাপের মধ্যে থাকা ত্রিমাত্রিক স্থানের (3D space) একটি অংশ, যেখানে আপনি ত্রিমাত্রিক কন্টেন্ট রাখতে, ত্রিমাত্রিক লেআউট তৈরি করতে এবং অন্যথায় দ্বিমাত্রিক (2D) কন্টেন্টে গভীরতা যোগ করতে পারেন। একটি সাবস্পেস শুধুমাত্র তখনই রেন্ডার করা হয় যখন স্পেশিয়ালাইজেশন (spatialization) সক্রিয় থাকে। হোম স্পেসে (Home Space) বা নন-XR ডিভাইসগুলিতে, সেই সাবস্পেসের ভেতরের যেকোনো কোড উপেক্ষা করা হয়।
সাবস্পেস তৈরি করার কয়েকটি উপায় আছে:
Subspace : এই কম্পোজেবলটি একটি নতুন, স্বাধীন স্পেশিয়াল UI হায়ারার্কি তৈরি করে। এটি যে প্যারেন্ট Subspace মধ্যে নেস্টেড থাকে, তার স্পেশিয়াল পজিশন, ওরিয়েন্টেশন বা স্কেল উত্তরাধিকার সূত্রে পায় না। Subspace স্বয়ংক্রিয়ভাবে সিস্টেমের প্রস্তাবিত কন্টেন্ট বক্স দ্বারা আবদ্ধ থাকে।
PlanarEmbeddedSubspace : এই কম্পোজেবলটি আপনার অ্যাপের UI হায়ারার্কির মধ্যে রাখা যেতে পারে, যা আপনাকে 2D এবং স্পেশিয়াল UI-এর লেআউট বজায় রাখতে সাহায্য করে। PlanarEmbeddedSubspace তার প্যারেন্টের সীমাবদ্ধতা এবং পজিশনিং মেনে চলে। এর ভিতরে রাখা 3D কন্টেন্ট তখন এই 2D-নির্ধারিত এলাকার সাপেক্ষে অবস্থান নেয়।
সাবস্পেস কম্পোজেবল : এই কম্পোনেন্টগুলো শুধুমাত্র একটি সাবস্পেসের মধ্যেই রেন্ডার করা যায়। একটি 2D লেআউটে স্থাপন করার আগে এগুলোকে অবশ্যই Subspace মধ্যে আবদ্ধ করতে হবে। একটি SubspaceModifier আপনাকে আপনার সাবস্পেস কম্পোজেবলগুলোতে ডেপথ, অফসেট এবং পজিশনিং- এর মতো অ্যাট্রিবিউট যোগ করার সুযোগ দেয়।
অন্যান্য স্পেশিয়ালাইজড কম্পোনেন্টগুলোকে সাবস্পেসের ভেতর থেকে কল করার প্রয়োজন হয় না। এগুলো একটি স্পেশিয়াল কন্টেইনারের মধ্যে মোড়ানো প্রচলিত ২ডি এলিমেন্ট নিয়ে গঠিত। এই এলিমেন্টগুলো ২ডি বা ৩ডি লেআউটের জন্য ব্যবহার করা যেতে পারে, যদি উভয়টির জন্যই এগুলো সংজ্ঞায়িত করা থাকে। যখন স্পেশিয়ালাইজেশন সক্রিয় থাকে না, তখন এদের স্পেশিয়ালাইজড ফিচারগুলো উপেক্ষা করা হয় এবং এগুলো তাদের ২ডি প্রতিরূপে ফিরে যায়।
একটি স্থানিক প্যানেল তৈরি করুন
একটি SpatialPanel হলো একটি কম্পোজেবল সাবস্পেস যা আপনাকে অ্যাপের কন্টেন্ট প্রদর্শন করতে দেয়—উদাহরণস্বরূপ, আপনি একটি স্পেশাল প্যানেলে ভিডিও প্লেব্যাক, স্থির চিত্র বা অন্য যেকোনো কন্টেন্ট প্রদর্শন করতে পারেন।
নিম্নলিখিত উদাহরণে দেখানো অনুযায়ী, আপনি SubspaceModifier ব্যবহার করে স্পেশিয়াল প্যানেলের আকার, আচরণ এবং অবস্থান পরিবর্তন করতে পারেন।
যেহেতু SpatialPanel API-গুলো সাবস্পেস কম্পোজেবল, তাই আপনাকে অবশ্যই এগুলোকে [ Subspace ][4]-এর ভিতরে কল করতে হবে। সাবস্পেসের বাইরে কল করলে একটি এক্সেপশন থ্রো হবে।
SubspaceModifier এর height এবং width স্পেসিফিকেশন ব্যবহার করে SpatialPanel এর আকার নির্ধারণ করা হয়েছে। এই স্পেসিফিকেশনগুলো বাদ দিলে প্যানেলের আকার তার ভেতরের বিষয়বস্তুর পরিমাপ অনুযায়ী নির্ধারিত হয়।
একটি MovePolicy যোগ করে ব্যবহারকারীকে প্যানেল সরানোর অনুমতি দিন।
একটি ResizePolicy যোগ করে ব্যবহারকারীকে প্যানেলের আকার পরিবর্তন করার অনুমতি দিন।
যখন কোনো ব্যবহারকারী একটি প্যানেলকে নিজের থেকে দূরে সরান, তখন ডিফল্টরূপে, একটি MovePolicy প্যানেলটিকে ঠিক সেভাবেই স্কেল করে যেভাবে হোম স্পেসে সিস্টেম প্যানেলগুলির আকার পরিবর্তন করে। এর সমস্ত চাইল্ড কন্টেন্ট এই আচরণটি গ্রহণ করে। এটি নিষ্ক্রিয় করতে, shouldScaleWithDistance প্যারামিটারটিকে false এ সেট করুন।
একটি অরবিটার তৈরি করুন
অরবিটার হলো একটি স্পেশিয়াল UI কম্পোনেন্ট। এটিকে সংশ্লিষ্ট স্পেশিয়াল প্যানেল অথবা স্পেশিয়াল লেআউট কম্পোনেন্ট, যেমন SpatialColumn , SpatialRow , বা SpatialBox এর সাথে সংযুক্ত করার জন্য ডিজাইন করা হয়েছে। একটি অরবিটারে সাধারণত সেই এনটিটির সাথে সম্পর্কিত নেভিগেশন এবং প্রাসঙ্গিক অ্যাকশন আইটেম থাকে, যার সাথে এটি অ্যাঙ্কর করা থাকে। উদাহরণস্বরূপ, যদি আপনি ভিডিও কন্টেন্ট দেখানোর জন্য একটি স্পেশিয়াল প্যানেল তৈরি করে থাকেন, তাহলে আপনি একটি অরবিটারের ভিতরে ভিডিও প্লেব্যাক কন্ট্রোল যোগ করতে পারেন।
নিচের উদাহরণে যেমন দেখানো হয়েছে, নেভিগেশনের মতো ইউজার কন্ট্রোলগুলোকে র্যাপ করার জন্য একটি SpatialPanel এর 2D লেআউটের ভিতরে একটি অরবিটার কল করুন। এটি করলে, ইউজার কন্ট্রোলগুলো আপনার 2D লেআউট থেকে এক্সট্র্যাক্ট হয়ে আপনার কনফিগারেশন অনুযায়ী স্পেশিয়াল প্যানেলে সংযুক্ত হয়ে যায়।
যেহেতু অরবিটারগুলো স্পেশিয়াল UI কম্পোনেন্ট, তাই এর কোড 2D বা 3D লেআউটে পুনরায় ব্যবহার করা যায়। একটি 2D লেআউটে, আপনার অ্যাপ শুধুমাত্র অরবিটারের ভেতরের কন্টেন্ট রেন্ডার করে এবং অরবিটারটিকে উপেক্ষা করে।
অরবিটার কীভাবে ব্যবহার ও ডিজাইন করতে হয়, সে সম্পর্কে আরও তথ্যের জন্য আমাদের ডিজাইন নির্দেশিকা দেখুন।
একটি স্থানিক বিন্যাসে একাধিক স্থানিক প্যানেল যোগ করুন
যেসব লেআউটে এক সারিতে একাধিক প্যানেল থাকে, সেগুলোর ক্ষেত্রে আমরা SubspaceModifier ব্যবহার করে 825dp-এর একটি কার্ভ রেডিয়াস সেট করার পরামর্শ দিই, যাতে প্যানেলগুলো আপনার ব্যবহারকারীকে ঘিরে রাখে। বিস্তারিত জানতে আমাদের ডিজাইন নির্দেশিকা দেখুন।
আপনার লেআউটে এনটিটি স্থাপন করতে একটি SceneCoreEntity ব্যবহার করুন।
আপনার লেআউটে একটি 3D অবজেক্ট স্থাপন করতে, আপনাকে SceneCoreEntity নামক একটি সাবস্পেস কম্পোজেবল ব্যবহার করতে হবে। এটি কীভাবে করতে হয় তার একটি উদাহরণ এখানে দেওয়া হলো।
Subspace{SceneCoreEntity(modifier=SubspaceModifier.offset(x=50.dp),factory={SurfaceEntity.create(session=session,pose=Pose.Identity,stereoMode=SurfaceEntity.StereoMode.MONO)},update={entity->
// compose state changes may be applied to the// SceneCore entity here.entity.stereoMode=SurfaceEntity.StereoMode.SIDE_BY_SIDE},sizeAdapter=SceneCoreEntitySizeAdapter({IntSize2d(it.width,it.height)}),){// Content here will be children of the SceneCoreEntity// in the scene graph.}}
একটি SceneCoreEntity মধ্যে কীভাবে 3D কন্টেন্ট লোড করতে হয় তা আরও ভালোভাবে বুঝতে, আপনার অ্যাপে 3D মডেল যোগ করুন দেখুন।
ছবি বা ভিডিও কন্টেন্টের জন্য একটি সারফেস যোগ করুন
SpatialExternalSurface হলো একটি কম্পোজেবল সাবস্পেস যা এমন একটি Surface তৈরি ও পরিচালনা করে, যেখানে আপনার অ্যাপ ছবি বা ভিডিওর মতো কন্টেন্ট ড্র করতে পারে। SpatialExternalSurface স্টেরিওস্কোপিক বা মনোস্কোপিক উভয় প্রকার কন্টেন্টই সমর্থন করে।
@OptIn(ExperimentalComposeApi::class)@ComposablefunSpatialExternalSurfaceContent(){valcontext=LocalContext.currentSubspace{SpatialExternalSurface(modifier=SubspaceModifier.width(1200.dp)// Default width is 400.dp if no width modifier is specified.height(676.dp),// Default height is 400.dp if no height modifier is specified// Use StereoMode.Mono, StereoMode.SideBySide, or StereoMode.TopBottom, depending// upon which type of content you are rendering: monoscopic content, side-by-side stereo// content, or top-bottom stereo contentstereoMode=StereoMode.SideBySide,){valexoPlayer=remember{ExoPlayer.Builder(context).build()}valvideoUri=Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)// Represents a side-by-side stereo video, where each frame contains a pair of// video frames arranged side-by-side. The frame on the left represents the left// eye view, and the frame on the right represents the right eye view..path("sbs_video.mp4").build()valmediaItem=MediaItem.fromUri(videoUri)// onSurfaceCreated is invoked only one time, when the Surface is createdonSurfaceCreated{surface->
exoPlayer.setVideoSurface(surface)exoPlayer.setMediaItem(mediaItem)exoPlayer.prepare()exoPlayer.play()}// onSurfaceDestroyed is invoked when the SpatialExternalSurface composable and its// associated Surface are destroyedonSurfaceDestroyed{exoPlayer.release()}}}}
আপনি কোন ধরনের কন্টেন্ট রেন্ডার করছেন তার উপর নির্ভর করে StereoModeMono , SideBySide বা TopBottom এ সেট করুন:
Mono : ছবি বা ভিডিও ফ্রেমটি একটি একক, অভিন্ন চিত্র নিয়ে গঠিত যা উভয় চোখেই দেখানো হয়।
SideBySide : এই ছবি বা ভিডিও ফ্রেমে পাশাপাশি সাজানো একজোড়া ছবি বা ভিডিও ফ্রেম থাকে, যেখানে বাম দিকের ছবি বা ফ্রেমটি বাম চোখের দৃশ্য এবং ডান দিকের ছবি বা ফ্রেমটি ডান চোখের দৃশ্যকে উপস্থাপন করে।
TopBottom : ছবি বা ভিডিও ফ্রেমটিতে উল্লম্বভাবে সজ্জিত একজোড়া ছবি বা ভিডিও ফ্রেম থাকে, যেখানে উপরের ছবি বা ফ্রেমটি বাম চোখের দৃশ্য এবং নিচের ছবি বা ফ্রেমটি ডান চোখের দৃশ্যকে উপস্থাপন করে।
অ্যাপ্লিকেশন রেন্ডারিং বা ভিডিও ডিকোডিংয়ের সাথে StereoMode পরিবর্তন সিঙ্ক্রোনাইজ করা সম্ভব নয়।
এই কম্পোজেবলটি অন্য প্যানেলের সামনে রেন্ডার হতে পারে না, তাই লেআউটে অন্য প্যানেল থাকলে আপনার MovePolicy ব্যবহার করা উচিত নয়।
DRM সুরক্ষিত ভিডিও কন্টেন্টের জন্য একটি পৃষ্ঠতল যোগ করুন
SpatialExternalSurface ডিআরএম-সুরক্ষিত ভিডিও স্ট্রিম প্লেব্যাকও সমর্থন করে। এটি সক্রিয় করতে, আপনাকে অবশ্যই একটি সুরক্ষিত সারফেস তৈরি করতে হবে যা সুরক্ষিত গ্রাফিক্স বাফারে রেন্ডার করে। এটি কন্টেন্টকে স্ক্রিন-রেকর্ড হওয়া বা অসুরক্ষিত সিস্টেম কম্পোনেন্ট দ্বারা অ্যাক্সেস হওয়া থেকে বিরত রাখে।
একটি সুরক্ষিত সারফেস তৈরি করতে, SpatialExternalSurface কম্পোজেবলে surfaceProtection প্যারামিটারটিকে SurfaceProtection.Protected এ সেট করুন। এছাড়াও, লাইসেন্স সার্ভার থেকে লাইসেন্স সংগ্রহের বিষয়টি পরিচালনা করার জন্য আপনাকে অবশ্যই উপযুক্ত DRM তথ্য দিয়ে Media3 Exoplayer কনফিগার করতে হবে।
নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি DRM-সুরক্ষিত ভিডিও স্ট্রিম চালানোর জন্য SpatialExternalSurface এবং ExoPlayer কনফিগার করতে হয়:
@OptIn(ExperimentalComposeApi::class)@ComposablefunDrmSpatialVideoPlayer(){valcontext=LocalContext.currentSubspace{SpatialExternalSurface(modifier=SubspaceModifier.width(1200.dp).height(676.dp),stereoMode=StereoMode.SideBySide,surfaceProtection=SurfaceProtection.Protected){valexoPlayer=remember{ExoPlayer.Builder(context).build()}// Define the URI for your DRM-protected content and license server.valvideoUri="https://your-content-provider.com/video.mpd"valdrmLicenseUrl="https://your-license-server.com/license"// Build a MediaItem with the necessary DRM configuration.valmediaItem=MediaItem.Builder().setUri(videoUri).setDrmConfiguration(MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID).setLicenseUri(drmLicenseUrl).build()).build()onSurfaceCreated{surface->
// The created surface is secure and can be used by the player.exoPlayer.setVideoSurface(surface)exoPlayer.setMediaItem(mediaItem)exoPlayer.prepare()exoPlayer.play()}onSurfaceDestroyed{exoPlayer.release()}}}}
সুরক্ষিত সারফেস: SpatialExternalSurface এ surfaceProtection = SurfaceProtection.Protected সেট করা অপরিহার্য, যাতে এর নিচের Surface DRM কন্টেন্টের জন্য উপযুক্ত সুরক্ষিত বাফার দ্বারা সুরক্ষিত থাকে।
ডিআরএম কনফিগারেশন: আপনাকে অবশ্যই ডিআরএম স্কিম (উদাহরণস্বরূপ, C.WIDEVINE_UUID ) এবং আপনার লাইসেন্স সার্ভারের ইউআরআই দিয়ে MediaItem কনফিগার করতে হবে। এক্সোপ্লেয়ার ডিআরএম সেশন পরিচালনা করার জন্য এই তথ্য ব্যবহার করে।
সুরক্ষিত কন্টেন্ট: কোনো সুরক্ষিত প্ল্যাটফর্মে রেন্ডার করার সময়, ভিডিও কন্টেন্টটি একটি সুরক্ষিত পথে ডিকোড ও প্রদর্শন করা হয়, যা কন্টেন্ট লাইসেন্সিংয়ের শর্ত পূরণ করতে সাহায্য করে। এটি কন্টেন্টটিকে স্ক্রিন ক্যাপচারে প্রদর্শিত হওয়া থেকেও বিরত রাখে।
অন্যান্য স্থানিক UI উপাদান যোগ করুন
স্পেশিয়াল UI কম্পোনেন্টগুলো আপনার অ্যাপ্লিকেশনের UI হায়ারার্কির যেকোনো স্থানে স্থাপন করা যেতে পারে। এই এলিমেন্টগুলো আপনার 2D UI-তে পুনরায় ব্যবহার করা যায়, এবং এদের স্পেশিয়াল অ্যাট্রিবিউটগুলো কেবল তখনই দৃশ্যমান হবে যখন স্পেশিয়াল ক্যাপাবিলিটিগুলো সক্রিয় করা থাকবে। এর ফলে, আপনার কোড দুবার না লিখেই মেনু, ডায়ালগ এবং অন্যান্য কম্পোনেন্টে এলিভেশন যোগ করা যায়। এই এলিমেন্টগুলো কীভাবে ব্যবহার করতে হয় তা আরও ভালোভাবে বোঝার জন্য স্পেশিয়াল UI-এর নিম্নলিখিত উদাহরণগুলো দেখুন।
UI উপাদান
যখন স্থানিকীকরণ সক্রিয় করা হয়
দ্বিমাত্রিক পরিবেশে
SpatialDialog
উন্নত ডায়ালগ প্রদর্শনের জন্য প্যানেলটি z-গভীরতায় সামান্য পিছিয়ে যাবে।
উচ্চতা যোগ করার জন্য SpatialElevationLevel সেট করা যেতে পারে।
স্থানিক উচ্চতা ছাড়া দেখানো হয়।
স্থানিক সংলাপ
এটি এমন একটি ডায়ালগের উদাহরণ যা অল্প বিলম্বের পর খোলে। যখন SpatialDialog ব্যবহার করা হয়, তখন ডায়ালগটি স্পেশিয়াল প্যানেলের সমান z-depth-এ প্রদর্শিত হয়, এবং স্পেশিয়ালাইজেশন সক্রিয় থাকলে প্যানেলটি 125dp পিছিয়ে যায়। স্পেশিয়ালাইজেশন সক্রিয় না থাকলেও SpatialDialog ব্যবহার করা যেতে পারে, সেক্ষেত্রে SpatialDialog তার 2D প্রতিরূপ, Dialog এ ফিরে যায়।
Compose for XR দ্বারা সমর্থিত নয় এমন কাস্টম প্যানেল তৈরি করতে, আপনি SceneCore API ব্যবহার করে সরাসরি PanelEntity ইনস্ট্যান্স এবং সিন গ্রাফের সাথে কাজ করতে পারেন।
মহাকাশ প্যানেল এবং বিন্যাসের সাথে অরবিটারগুলিকে নোঙর করুন
আপনি কম্পোজে ঘোষিত SpatialPanels এবং স্পেশাল লেআউট কম্পোনেন্টগুলিতে একটি অরবিটার অ্যাঙ্কর করতে পারেন। এর জন্য SpatialRow , SpatialColumn বা SpatialBox মতো UI এলিমেন্টের একটি স্পেশাল লেআউটে অরবিটার ঘোষণা করতে হয়। অরবিটারটি আপনার ঘোষণার স্থানের সবচেয়ে কাছের প্যারেন্টের সাথে অ্যাঙ্কর হয়।
অরবিটারটির আচরণ নির্ধারিত হয় আপনি এটিকে কোথায় ঘোষণা করছেন তার উপর:
একটি SpatialPanel এ মোড়ানো 2D লেআউটে (যেমনটি পূর্ববর্তী কোড স্নিপেটে দেখানো হয়েছে), অরবিটারটি সেই SpatialPanel সাথে অ্যাঙ্কর করে।
একটি Subspace মধ্যে, অরবিটারটি তার নিকটতম প্যারেন্ট এনটিটির সাথে নোঙর করে, যা হলো সেই স্পেশিয়াল লেআউট যেখানে অরবিটারটি ঘোষিত হয়েছে।
নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি অরবিটারকে একটি স্থানিক সারিতে নোঙর করতে হয়:
যখন আপনি একটি 2D লেআউটের বাইরে কোনো অরবিটার ডিক্লেয়ার করেন, তখন অরবিটারটি তার নিকটতম প্যারেন্ট এনটিটির সাথে অ্যাঙ্কর করে। এই ক্ষেত্রে, অরবিটারটি যে SpatialRow তে ডিক্লেয়ার করা হয়েছে, তার শীর্ষে অ্যাঙ্কর করে।
SpatialRow , SpatialColumn , SpatialBox এর মতো স্পেশিয়াল লেআউটগুলোর সাথে বিষয়বস্তুহীন এনটিটি যুক্ত থাকে। তাই, একটি স্পেশিয়াল লেআউটে ঘোষিত অরবিটার সেই লেআউটটিকে অ্যাঙ্কর করে।
এই পৃষ্ঠার কন্টেন্ট ও কোডের নমুনাগুলি Content License-এ বর্ণিত লাইসেন্সের অধীনস্থ। Java এবং OpenJDK হল Oracle এবং/অথবা তার অ্যাফিলিয়েট সংস্থার রেজিস্টার্ড ট্রেডমার্ক।
2026-04-09 UTC-তে শেষবার আপডেট করা হয়েছে।
[[["সহজে বোঝা যায়","easyToUnderstand","thumb-up"],["আমার সমস্যার সমাধান হয়েছে","solvedMyProblem","thumb-up"],["অন্যান্য","otherUp","thumb-up"]],[["এতে আমার প্রয়োজনীয় তথ্য নেই","missingTheInformationINeed","thumb-down"],["খুব জটিল / অনেক ধাপ","tooComplicatedTooManySteps","thumb-down"],["পুরনো","outOfDate","thumb-down"],["অনুবাদ সংক্রান্ত সমস্যা","translationIssue","thumb-down"],["নমুনা / কোড সংক্রান্ত সমস্যা","samplesCodeIssue","thumb-down"],["অন্যান্য","otherDown","thumb-down"]],["2026-04-09 UTC-তে শেষবার আপডেট করা হয়েছে।"],[],[]]