সিন ডেকোরেটর ব্যবহার করে দৃশ্য পরিবর্তন করা

আপনার অ্যাপের সিন স্ট্র্যাটেজি দ্বারা গণনা করা সিনকে সিন ডেকোরেটর পরিবর্তন করতে দেয়। প্রকৃতপক্ষে, এগুলি NavDisplay-এর মাধ্যমে দেখানো কন্টেন্ট তৈরির দ্বিতীয় ধাপে ব্যবহার করা হয়।

এই পদ্ধতির মাধ্যমে আপনি নির্দিষ্ট ফাংশনালিটি, যেমন সাধারণ UI কম্পোনেন্ট দেখানো ইত্যাদিকে আলাদা আলাদা সিন ডেকোরেটরে এনক্যাপসুলেট করতে পারবেন।

যেমন, প্রোডাক্টিভিটি অ্যাপের কথা বিবেচনা করুন, যার তিনটি টপ-লেভেল রুট আছে: একটি ইমেল ইনবক্স, একটি ডাইরেক্ট মেসেজ ইনবক্স এবং একটি ক্যালেন্ডার ভিউ। এই ধরনের অ্যাপ দুটি সিন ডেকোরেটর ব্যবহার করতে পারে, একটি হল বর্তমান টপ-লেভেল রুটের জন্য তথ্য ও কন্ট্রোল দেখানো টপ অ্যাপ বার যোগ করার জন্য এবং অন্যটি হল রুটগুলির মধ্যে নেভিগেট করার জন্য একটি পারসিস্টেন্ট নেভিগেশন বার বা রেল যোগ করার জন্য।

সিন ডেকোরেটর স্ট্র্যাটেজি তৈরি করা

দৃশ্য সজ্জাকাররা দৃশ্য কৌশল হিসেবে একই ধরনের প্যাটার্ন অনুসরণ করে। কোনও দৃশ্য ডেকোরেটরকে সংজ্ঞায়িত করতে, SceneDecoratorStrategy ইন্টারফেস প্রয়োগ করুন। এই ইন্টারফেসে decorateScene নামে একটি পদ্ধতি আছে, যা SceneStrategy ইন্টারফেসের calculateScene পদ্ধতির মতো। decorateScene নির্ধারণ করে যে এটি দৃশ্য সাজাতে পারবে কিনা:

  • আপনার সিন ডেকোরেটর স্ট্র্যাটেজি ইনপুট সিনকে সাজানোর কথা না থাকলে, এটি ইনপুট সিনকে যেমন আছে তেমনই রিটার্ন করে।
  • ইনপুট সিনকে সাজানোর কথা থাকলে, এটি একটি নতুন Scene রিটার্ন করে। সাধারণভাবে, রিটার্ন করা দৃশ্য ইনপুট দৃশ্যকে প্যারামিটার হিসেবে নেয় এবং ইনপুট দৃশ্যের content মেথডকে নিজের content মেথডের মধ্যে কল করে।

ইনপুট সিন কীভাবে সাজানো উচিত তা নির্ধারণ করতে, আপনার সিন ডেকোরেটর স্ট্র্যাটেজি ইনপুট Scene এবং সেই সিনের মধ্যে থাকা এন্ট্রি, দুটিরই মেটাডেটা বিবেচনা করতে পারে।

class MySceneDecoratorStrategy<T : Any> : SceneDecoratorStrategy<T> {


    override fun SceneDecoratorStrategyScope<T>.decorateScene(scene: Scene<T>): Scene<T> {
        // `shouldDecorate` determines if the scene should be decorated based on scene.metadata,
        // scene.entries.metadata, or any other relevant state.
        return if (shouldDecorate(scene)) {
            MyDecoratingScene(scene)
        } else {
            scene
        }
    }

}

data class MyDecoratingScene<T : Any>(
    val scene: Scene<T>
) : Scene<T> {

    // ...

    override val content = @Composable {
        scene.content()
    }
}

সিন ডেকোরেটর স্ট্র্যাটেজি ব্যবহার করা

সিন ডেকোরেটর স্ট্র্যাটেজি ব্যবহার করতে, NavDisplay-এ sceneDecoratorStrategies প্যারামিটার ব্যবহার করে সেগুলি সাপ্লাই করুন। দৃশ্য সাজানোর সময়, NavDisplay কল করে প্রতিটি স্ট্র্যাটেজির decorateScene মেথডকে পরপর, প্রতিটি কলের আউটপুটকে পরের কলের ইনপুট হিসেবে পাস করে।

NavDisplay(
    // ...
    sceneDecoratorStrategies = listOf(firstSceneDecoratorStrategy, secondSceneDecoratorStrategy)
)

সিন ডেকোরেটরদের জন্য সাধারণ প্যাটার্ন

সিন ডেকোরেটর প্রয়োগ করার সময়, নিম্নলিখিত সাধারণ প্যাটার্নগুলি সম্পর্কে সচেতন থাকতে হবে:

প্রপার্টি কপি করা

অনেক ক্ষেত্রে, কোনও সিনকে সাজিয়ে যে সিন রিটার্ন করা হয়, সেটিতে একই এন্ট্রি থাকতে হবে এবং যে সিনকে সাজানো হচ্ছে সেটির মতো একই আগের এন্ট্রি থাকতে হবে। এছাড়াও, এটি যে সিনকে সাজাচ্ছে, সেটির মেটাডেটা সম্ভবত ইনহেরিট (বা পরিবর্তন) করা উচিত ডিফল্ট আচরণ ব্যবহার করার পরিবর্তে। নিচে দেওয়া কোড থেকে কীভাবে এটি করতে হয় তার একটি উদাহরণ পাওয়া যায়:

data class CopyingScene<T : Any>(
    val scene: Scene<T>
) : Scene<T> {
    override val entries = scene.entries
    override val previousEntries = scene.previousEntries
    override val metadata = scene.metadata

    // ...
}

অ্যানিমেশন বজায় রাখা

দুটি গন্তব্যের মধ্যে অ্যানিমেট করা নিবন্ধে বিস্তারিতভাবে বলা হয়েছে যে, বর্তমান দৃশ্যের ক্লাস থেকে প্রাপ্ত কী এবং এর key প্রপার্টি পরিবর্তন হলে, NavDisplay অটোমেটিক দৃশ্যগুলির মধ্যে ট্রানজিশন অ্যানিমেট করে।

আপনার অ্যাপে সিন ডেকোরেটর যোগ করার সময়, সিন ডেকোরেশনের পরে ফেরত আসা সিন ক্লাস একই থাকতে পারে, এমনকি সিন ক্যালকুলেশন চলাকালীন ফেরত আসা সিন ক্লাস পরিবর্তন হলেও। এটি ঘটলে এবং সাজানো দৃশ্য সরাসরি সেই দৃশ্যের key কপি করলে, যে দৃশ্য তারা সাজাচ্ছে, তাহলে বিল্ট-ইন অ্যানিমেশন আর হয় না কারণ প্রাপ্ত কী পরিবর্তন হয় না।

বিল্ট-ইন অ্যানিমেশন সাপোর্ট বজায় রাখতে, সিনের সাজসজ্জায় calculateScene-এর মাধ্যমে রিটার্ন করা সিনের ক্লাস ও key থেকে প্রাপ্ত কী ব্যবহার করা উচিত।

data class DerivedKeyScene<T : Any>(
    val scene: Scene<T>
) : Scene<T> {
    override val key = scene::class to scene.key

    // ...
}