कैसे करें

पेश है Cahier: बड़ी स्क्रीन पर प्रॉडक्टिविटी और क्रिएटिविटी के लिए, Android का नया GitHub सैंपल

11 मिनट में पढ़ा जा सकता है
क्रिस असिग्बे की प्रोफ़ाइल देखें
Chris Assigbe डेवलपर रिलेशंस इंजीनियर

Ink API अब बीटा वर्शन में उपलब्ध है. इसे अपने ऐप्लिकेशन में इंटिग्रेट किया जा सकता है. यह उपलब्धि, डेवलपर से मिले सुझावों की वजह से हासिल हुई है. इससे एपीआई की परफ़ॉर्मेंस, स्थिरता, और विज़ुअल क्वालिटी में लगातार सुधार हो रहा है.

Google के ऐप्लिकेशन, जैसे कि Google Docs, Pixel Studio, Google Photos, Chrome PDF, YouTube Effect Maker और Android की यूनीक सुविधाएं, जैसे कि सर्कल बनाकर ढूंढें, ये सभी नए एपीआई का इस्तेमाल करते हैं. 

इस उपलब्धि को यादगार बनाने के लिए, हमें Cahier लॉन्च करते हुए खुशी हो रही है. यह नोट लेने वाला एक ऐप्लिकेशन सैंपल है. इसे सभी साइज़ के Android डिवाइसों के लिए ऑप्टिमाइज़ किया गया है. खास तौर पर, टैबलेट और फ़ोल्ड किए जा सकने वाले फ़ोन के लिए.

Cahier क्या है?

Cahier (फ़्रेंच में "नोटबुक") एक सैंपल के तौर पर मिला ऐप्लिकेशन है. इसे यह दिखाने के लिए डिज़ाइन किया गया है कि टेक्स्ट, ड्रॉइंग, और इमेज को मिलाकर, ऐसा ऐप्लिकेशन कैसे बनाया जा सकता है जिसकी मदद से लोग अपने विचारों को कैप्चर और व्यवस्थित कर सकें.

इस सैंपल का इस्तेमाल, बड़ी स्क्रीन पर उपयोगकर्ताओं की प्रोडक्टिविटी और क्रिएटिविटी को बेहतर बनाने के लिए किया जा सकता है. इसमें इस तरह के अनुभव बनाने के सबसे सही तरीके दिखाए गए हैं. इससे डेवलपर को, इससे जुड़े पावरफ़ुल एपीआई और तकनीकों को समझने और उन्हें अपनाने में मदद मिलती है. इस पोस्ट में, Cahier की मुख्य सुविधाओं, मुख्य एपीआई, और आर्किटेक्चर से जुड़े फ़ैसलों के बारे में बताया गया है. इससे यह सैंपल, आपके ऐप्लिकेशन के लिए एक बेहतरीन रेफ़रंस बन जाता है.

इस सैंपल में दिखाई गई मुख्य सुविधाएं ये हैं:

  • नोट बनाने के कई तरीके: इसमें कॉन्टेंट बनाने के ऐसे सिस्टम को लागू करने का तरीका बताया गया है जो एक ही नोट में कई फ़ॉर्मैट में कॉन्टेंट बनाने की सुविधा देता है. जैसे, टेक्स्ट, फ़्रीफ़ॉर्म ड्रॉइंग, और इमेज अटैचमेंट.
  • क्रिएटिव इंक टूल: Ink API का इस्तेमाल करके, ड्राइंग का बेहतरीन अनुभव देता है. इसमें कम लेटेंसी होती है. इस सैंपल में, अलग-अलग ब्रशिंग, कलर पिकर, पहले जैसा करें/दोबारा करें सुविधा, और मिटाने वाले टूल को इंटिग्रेट करने का एक प्रैक्टिकल उदाहरण दिया गया है.
  • खींचें और छोड़ें सुविधा के साथ फ़्लूड कॉन्टेंट इंटिग्रेशन: इसमें बताया गया है कि खींचें और छोड़ें सुविधा का इस्तेमाल करके, आने वाले और जाने वाले कॉन्टेंट, दोनों को कैसे मैनेज किया जाता है. इसमें, दूसरे ऐप्लिकेशन से ड्रॉप की गई इमेज स्वीकार करना और उपयोगकर्ताओं को आसानी से कॉन्टेंट शेयर करने के लिए, आपके ऐप्लिकेशन से कॉन्टेंट को ड्रैग करने की सुविधा देना शामिल है.
  • नोट व्यवस्थित करना: नोट को पसंदीदा के तौर पर मार्क करें, ताकि उन्हें आसानी से ऐक्सेस किया जा सके. व्यू को फ़िल्टर करके, व्यवस्थित रहें.
  • ऑफ़लाइन फ़र्स्ट आर्किटेक्चर:  इसे ऑफ़लाइन फ़र्स्ट आर्किटेक्चर का इस्तेमाल करके बनाया गया है. इसमें Room का इस्तेमाल किया गया है. इससे यह पक्का किया जाता है कि सभी डेटा को स्थानीय तौर पर सेव किया जाए और ऐप्लिकेशन बिना इंटरनेट कनेक्शन के पूरी तरह से काम करता रहे.
  • मल्टी-विंडो और एक से ज़्यादा इंस्टेंस इस्तेमाल करने की सुविधा: इसमें बताया गया है कि एक से ज़्यादा इंस्टेंस इस्तेमाल करने की सुविधा कैसे काम करती है. इससे आपके ऐप्लिकेशन को मल्टी-विंडो में लॉन्च किया जा सकता है. इससे उपयोगकर्ता, अलग-अलग नोट पर एक साथ काम कर सकते हैं. साथ ही, बड़ी स्क्रीन पर उनकी क्रिएटिविटी और प्रॉडक्टिविटी बढ़ती है.
  • सभी स्क्रीन के लिए अडैप्टिव यूज़र इंटरफ़ेस (यूआई): यूज़र इंटरफ़ेस (यूआई), ListDetailPaneScaffold और NavigationSuiteScaffold का इस्तेमाल करके, अलग-अलग स्क्रीन साइज़ और ओरिएंटेशन के हिसाब से अपने-आप अडजस्ट हो जाता है. इससे फ़ोन, टैबलेट, और फ़ोल्ड किए जा सकने वाले डिवाइसों पर उपयोगकर्ताओं को बेहतर अनुभव मिलता है.
  • सिस्टम के साथ बेहतर तरीके से इंटिग्रेट करना: इसमें Android 14 और इसके बाद के वर्शन पर, अपने ऐप्लिकेशन को नोट लेने वाले डिफ़ॉल्ट ऐप्लिकेशन के तौर पर सेट करने के बारे में गाइड दी गई है. इसके लिए, सिस्टम के सभी नोट इंटेंट का जवाब देना होगा. इससे, सिस्टम के अलग-अलग एंट्री पॉइंट से कॉन्टेंट को तुरंत कैप्चर किया जा सकेगा.

बड़ी स्क्रीन पर बेहतर प्रॉडक्टिविटी और क्रिएटिविटी के लिए बनाया गया

शुरुआत में, हम इस सूचना में कुछ मुख्य सुविधाओं के बारे में बता रहे हैं. ये सुविधाएं, Cahier को क्रिएटिविटी और बेहतर तरीके से काम करने के लिए एक अहम संसाधन बनाती हैं.

अडैप्टिविटी की बुनियादी बातें

Cahier को शुरू से ही अडैप्टिव बनाया गया है. इस सैंपल में, material3-adaptive लाइब्रेरी का इस्तेमाल किया गया है. खास तौर पर, ListDetailPaneScaffold और NavigationSuiteScaffold का इस्तेमाल किया गया है, ताकि ऐप्लिकेशन के लेआउट को अलग-अलग स्क्रीन साइज़ और ओरिएंटेशन के हिसाब से आसानी से अडजस्ट किया जा सके. यह आधुनिक Android ऐप्लिकेशन के लिए एक ज़रूरी एलिमेंट है. Cahier में, इसे असरदार तरीके से लागू करने का एक उदाहरण दिया गया है.

Cahier का अडैप्टिव यूज़र इंटरफ़ेस (यूआई), Material 3 अडैप्टिव लाइब्रेरी की मदद से बनाया गया है..gif

Material 3 अडैप्टिव लाइब्रेरी की मदद से बनाया गया Cahier अडैप्टिव यूज़र इंटरफ़ेस

मुख्य एपीआई और इंटिग्रेशन दिखाना

इस सैंपल में, बेहतर ढंग से काम करने में मदद करने वाले एपीआई दिखाए गए हैं. इनका इस्तेमाल अपने ऐप्लिकेशन में किया जा सकता है. इनमें ये एपीआई शामिल हैं:

मुख्य एपीआई के बारे में ज़्यादा जानकारी

आइए, Cahier के दो मुख्य एपीआई के बारे में ज़्यादा जानें. Cahier, इन एपीआई को इंटिग्रेट करके नोट लेने की बेहतरीन सुविधा देता है.

Ink API की मदद से, नैचुरल इंक स्ट्रोक बनाने की सुविधा

स्टाइलस की मदद से इनपुट करने की सुविधा, बड़ी स्क्रीन वाले डिवाइसों को डिजिटल नोटबुक और स्केचबुक में बदल देती है. आपको नैचुरल और बेहतरीन इंक स्ट्रोक बनाने में मदद करने के लिए, हमने Ink API को सैंपल का मुख्य हिस्सा बनाया है. Ink API की मदद से, बेहतरीन इंक स्ट्रोक बनाना, उन्हें रेंडर करना, और उनमें बदलाव करना आसान हो जाता है. साथ ही, इसमें इंतज़ार का समय भी कम लगता है.

Ink API में मॉड्यूलर आर्किटेक्चर होता है. इसलिए, इसे अपने ऐप्लिकेशन के स्टैक और ज़रूरतों के हिसाब से बनाया जा सकता है. एपीआई मॉड्यूल में ये शामिल हैं:

  • लेखन मॉड्यूल (Composeviews): यह मॉड्यूल, डिवाइस पर रीयलटाइम में इंक इनपुट को हैंडल करता है. इससे डिवाइस पर कम से कम समय में स्मूद स्ट्रोक बनाए जा सकते हैं.
    • DrawingSurface में, Cahier ने स्टाइलस या टच इनपुट को रीयलटाइम में हैंडल करने के लिए, हाल ही में लॉन्च किए गए InProgressStrokes कंपोज़ेबल का इस्तेमाल किया है. यह मॉड्यूल, पॉइंटर इवेंट कैप्चर करने और कम से कम इंतज़ार के समय में गीली स्याही के स्ट्रोक रेंडर करने के लिए ज़िम्मेदार होता है.
  • स्ट्रोक मॉड्यूल: यह इंक इनपुट और उसके विज़ुअल प्रज़ेंटेशन को दिखाता है.  जब कोई उपयोगकर्ता लाइन खींचना पूरा कर लेता है, तब onStrokesFinished कॉलबैक, ऐप्लिकेशन को फ़ाइनल/ड्राई Stroke ऑब्जेक्ट उपलब्ध कराता है. यह अपरिवर्तनीय ऑब्जेक्ट, इंक स्ट्रोक को दिखाता है. इसके बाद, इसे DrawingCanvasViewModel में मैनेज किया जाता है.
  • रेंडरिंग मॉड्यूल: यह मॉड्यूल, इंक स्ट्रोक को बेहतर तरीके से दिखाता है. इससे उन्हें Jetpack Compose या Android व्यू के साथ जोड़ा जा सकता है.
    • Cahier, मौजूदा और नए स्ट्रोक, दोनों को दिखाने के लिए DrawingSurface में CanvasStrokeRenderer का इस्तेमाल करता है. इसका इस्तेमाल, ऐक्टिव ड्राइंग के लिए किया जाता है. साथ ही, यह नोट की स्टैटिक झलक दिखाने के लिए DrawingDetailPanePreview में भी इस्तेमाल होता है. यह मॉड्यूल, स्ट्रोक ऑब्जेक्ट को कैनवस पर आसानी से बनाता है.
  • ब्रश मॉड्यूल (Composeviews): ये स्ट्रोक की विज़ुअल स्टाइल को तय करने का तरीका बताते हैं. हाल ही के अपडेट (alpha03 रिलीज़ के बाद से) में, एक नया डैश वाली लाइन का ब्रश शामिल है. यह खास तौर पर, लासो सिलेक्शन जैसी सुविधाओं के लिए उपयोगी है. DrawingCanvasViewModel, currentBrush के लिए स्थिति को सेव करता है. DrawingCanvas में मौजूद टूलबॉक्स की मदद से, लोग अलग-अलग तरह के ब्रश (जैसे, StockBrushes.pressurePen() या StockBrushes.highlighter()) चुन सकते हैं और उनके रंग बदल सकते हैं. ViewModel, Brush ऑब्जेक्ट को अपडेट करता है. इसके बाद, InProgressStrokes कंपोज़ेबल, नए स्ट्रोक के लिए इसका इस्तेमाल करता है.
  • ज्यामिति मॉड्यूल (Composeviews): मिटाने और चुनने जैसी सुविधाओं के लिए, स्ट्रोक में बदलाव करने और उनका विश्लेषण करने की सुविधा देता है.
    • टूलबॉक्स में मौजूद मिटाने वाला टूल और DrawingCanvasViewModel में मौजूद फ़ंक्शन, ज्यामिति मॉड्यूल पर निर्भर करते हैं. इरेज़र चालू होने पर, यह उपयोगकर्ता के जेस्चर के पाथ के चारों ओर एक MutableParallelogram बनाता है. इसके बाद, मिटाने वाला टूल, मौजूदा स्ट्रोक के शेप और बाउंडिंग बॉक्स के बीच इंटरसेक्शन की जांच करता है. इससे यह तय किया जाता है कि किन स्ट्रोक को मिटाना है. इससे मिटाने वाला टूल, सटीक और आसानी से इस्तेमाल किया जा सकता है.
  • स्टोरेज मॉड्यूल: यह मॉड्यूल, इंक डेटा को बेहतर तरीके से क्रम से लगाने और क्रम से हटाने की सुविधाएं देता है. इससे डिस्क और नेटवर्क के साइज़ में काफ़ी बचत होती है. ड्रॉइंग सेव करने के लिए, Cahier अपने Room डेटाबेस में Stroke ऑब्जेक्ट सेव करता है. कन्वर्टर में, सैंपल, स्टोरेज मॉड्यूल के encode फ़ंक्शन का इस्तेमाल करता है. इससे StrokeInputBatch (पॉइंट का रॉ डेटा) को ByteArray में क्रम से लगाया जाता है. बाइट ऐरे को ब्रशिंग प्रॉपर्टी के साथ JSON स्ट्रिंग के तौर पर सेव किया जाता है. नोट लोड होने पर, स्ट्रोक को फिर से बनाने के लिए decode फ़ंक्शन का इस्तेमाल किया जाता है.
orion.png

इन मुख्य मॉड्यूल के अलावा, हाल ही के अपडेट में Ink API की क्षमताओं को बढ़ाया गया है:

  • कस्टम BrushFamily ऑब्जेक्ट के लिए, एक्सपेरिमेंट के तौर पर उपलब्ध नए एपीआई की मदद से डेवलपर, क्रिएटिव और यूनीक ब्रश टाइप बना सकते हैं. इससे पेंसिल और लेज़र पॉइंटर जैसे टूल के लिए ब्रश बनाने की संभावनाएं मिलती हैं.

Cahier, क्रिएटिविटी को बेहतर बनाने के लिए कस्टम ब्रश का इस्तेमाल करता है. इनमें नीचे दिखाया गया यूनीक म्यूज़िक ब्रश भी शामिल है.

Ink API के कस्टम ब्रश की मदद से बनाया गया रेनबो लेज़र..gif

Ink API के कस्टम ब्रश की मदद से बनाया गया रेनबो लेज़र

notes.png

Ink API के कस्टम ब्रश की मदद से बनाया गया म्यूज़िक ब्रश

  • नेटिव Jetpack Compose इंटरऑपरेबिलिटी मॉड्यूल, इंक करने की सुविधाओं को सीधे तौर पर आपके Compose यूज़र इंटरफ़ेस में इंटिग्रेट करने की प्रोसेस को आसान बनाते हैं. इससे आपको डेवलपमेंट का बेहतर और ज़्यादा असरदार अनुभव मिलता है.

Ink API से कई फ़ायदे मिलते हैं. इस वजह से, यह प्रॉडक्टिविटी और क्रिएटिविटी ऐप्लिकेशन के लिए, कस्टम तरीके से लागू करने के मुकाबले बेहतर विकल्प है:

  • इस्तेमाल में आसान: Ink API, ग्राफ़िक और ज्यामिति की जटिलताओं को कम करता है. इससे आपको Cahier की मुख्य सुविधाओं पर फ़ोकस करने में मदद मिलती है.
  • परफ़ॉर्मेंस: इसमें पहले से मौजूद, स्टाइल के ज़रिए किए जाने वाले अनुरोधों को पूरा करने में लगने वाले समय को कम करने की सुविधा होती है. साथ ही, रेंडरिंग को ऑप्टिमाइज़ किया जाता है. इससे, इंक स्ट्रोक इस्तेमाल करने का अनुभव बेहतर और रिस्पॉन्सिव होता है.
  • लचीलापन: मॉड्यूलर डिज़ाइन की वजह से, ज़रूरत के हिसाब से कॉम्पोनेंट चुने जा सकते हैं. इससे Ink API को Cahier के आर्किटेक्चर में आसानी से इंटिग्रेट किया जा सकता है.

Ink API को पहले से ही Google के कई ऐप्लिकेशन में इस्तेमाल किया जा रहा है. जैसे, Docs में मार्कअप करने के लिए, 'सर्कल बनाकर ढूंढें' सुविधा के लिए, और Orion Notes और PDF Scanner जैसे पार्टनर ऐप्लिकेशन के लिए.

“सर्कल बनाकर ढूंढने की सुविधा (सीटीएस) के लिए, Ink API हमारी पहली पसंद था. Ink API को इंटिग्रेट करना बहुत आसान था, क्योंकि इसका दस्तावेज़ बहुत ज़्यादा जानकारी वाला है. इससे हमें सिर्फ़ एक हफ़्ते में, काम करने वाला पहला प्रोटोटाइप बनाने में मदद मिली. Ink में, कस्टम ब्रश टेक्सचर और ऐनिमेशन की सुविधा उपलब्ध है. इससे हमें स्ट्रोक डिज़ाइन को तुरंत दोहराने में मदद मिली.” - जॉर्डन कोमोडा, सॉफ़्टवेयर इंजीनियर - Google

नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट ऐप्लिकेशन के तौर पर सेट करना

नोट लेने की सुविधा, बड़ी स्क्रीन वाले डिवाइसों पर उपयोगकर्ता की प्रोडक्टिविटी बढ़ाने में अहम भूमिका निभाती है. नोट लिखने की सुविधा की मदद से, उपयोगकर्ता लॉक स्क्रीन से या अन्य ऐप्लिकेशन इस्तेमाल करते समय, आपके साथ काम करने वाले ऐप्लिकेशन को ऐक्सेस कर सकते हैं. इस सुविधा की मदद से, पूरे सिस्टम के लिए नोट लेने वाले डिफ़ॉल्ट ऐप्लिकेशन की पहचान की जाती है और उन्हें सेट किया जाता है. साथ ही, उन्हें कॉन्टेंट कैप्चर करने के लिए लॉन्च करने की अनुमति दी जाती है. 

Cahier में लागू करना

नोट्स की भूमिका को लागू करने के लिए, कुछ ज़रूरी चरण शामिल होते हैं. इन सभी को सैंपल में दिखाया गया है:

  1. मेनिफ़ेस्ट में एलान: सबसे पहले, ऐप्लिकेशन को नोट लेने के इंटेंट को हैंडल करने की अपनी क्षमता का एलान करना होगा. Cahier, AndroidManifest.xml में android.intent.action.CREATE_NOTE कार्रवाई के लिए <intent-filter> शामिल करता है. इससे सिस्टम को यह सिग्नल मिलता है कि ऐप्लिकेशन, नोट की भूमिका के लिए एक संभावित उम्मीदवार है.
  2. भूमिका की स्थिति की जांच करनाSettingsViewModel, मौजूदा स्थिति का पता लगाने के लिए Android के RoleManager का इस्तेमाल करता है. SettingsViewModel यह जांच करता है कि डिवाइस पर नोट की भूमिका उपलब्ध है या नहीं (isRoleAvailable). साथ ही, यह भी जांच करता है कि Cahier के पास फ़िलहाल वह भूमिका है या नहीं (isRoleHeld). इस स्थिति को Kotlin फ़्लो का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) पर दिखाया जाता है.
  3. भूमिका का अनुरोध करना: अगर भूमिका उपलब्ध है, लेकिन उपयोगकर्ता के पास नहीं है, तो Settings.kt फ़ाइल में उपयोगकर्ता को Button दिखता है. इस बटन पर क्लिक करने पर, ViewModel में मौजूद requestNotesRole फ़ंक्शन कॉल होता है. यह फ़ंक्शन, डिफ़ॉल्ट ऐप्लिकेशन की सेटिंग स्क्रीन खोलने के लिए एक इंटेंट बनाता है. इस स्क्रीन पर उपयोगकर्ता, Cahier को चुन सकता है. इस प्रोसेस को rememberLauncherForActivityResult एपीआई का इस्तेमाल करके मैनेज किया जाता है. यह एपीआई, इंटेंट लॉन्च करने और नतीजे पाने की प्रोसेस को मैनेज करता है.
  4. यूज़र इंटरफ़ेस (यूआई) अपडेट करना: जब उपयोगकर्ता सेटिंग स्क्रीन से वापस आता है, तो ActivityResultLauncher कॉलबैक, ViewModel में एक फ़ंक्शन को ट्रिगर करता है. इससे भूमिका का स्टेटस अपडेट हो जाता है. इससे यह पक्का होता है कि यूज़र इंटरफ़ेस (यूआई) में यह सही तरीके से दिखे कि ऐप्लिकेशन अब डिफ़ॉल्ट ऐप्लिकेशन है या नहीं.

हमारे नोट लेने वाला ऐप्लिकेशन बनाने की गाइड में, अपने ऐप्लिकेशन में नोट की भूमिका को इंटिग्रेट करने का तरीका जानें.

helloworld.png

Lenovo टैबलेट पर, नोट लेने के लिए डिफ़ॉल्ट ऐप्लिकेशन के तौर पर Cahier को फ़्लोटिंग विंडो में लॉन्च किया गया

एक बड़ा कदम: Lenovo ने नोट लेने की सुविधा चालू की

हमें यह बताते हुए खुशी हो रही है कि बड़ी स्क्रीन वाले Android डिवाइसों पर काम करने की सुविधा को बेहतर बनाने के लिए, हमने एक अहम कदम उठाया है: Lenovo ने Android 15 और इसके बाद के वर्शन पर चलने वाले टैबलेट पर, Notes Role की सुविधा चालू कर दी है! इस अपडेट के बाद, अब नोट लेने वाले ऐप्लिकेशन को अपडेट किया जा सकता है. इससे, Lenovo के साथ काम करने वाले डिवाइसों का इस्तेमाल करने वाले लोग, इन ऐप्लिकेशन को डिफ़ॉल्ट ऐप्लिकेशन के तौर पर सेट कर पाएंगे. इससे उन्हें लॉक स्क्रीन से बिना किसी रुकावट के ऐक्सेस मिलेगा. साथ ही, वे सिस्टम लेवल पर कॉन्टेंट कैप्चर करने की सुविधाओं को अनलॉक कर पाएंगे.

एक प्रमुख ओईएम की ओर से यह प्रतिबद्धता, Android पर उपयोगकर्ता अनुभव को बेहतर बनाने में नोट्स की बढ़ती हुई अहमियत को दिखाती है. 

मल्टी-इंस्टेंस, मल्टी-विंडोइंग, और डेस्कटॉप विंडोइंग

बड़ी स्क्रीन पर बेहतर तरीके से काम करने के लिए, जानकारी और वर्कफ़्लो को असरदार तरीके से मैनेज करना ज़रूरी है. इसलिए, Cahier को Android की ऐडवांस विंडो की सुविधाओं के साथ काम करने के लिए बनाया गया है. इससे उपयोगकर्ताओं को एक ऐसा वर्कस्पेस मिलता है जो उनकी ज़रूरतों के हिसाब से काम करता है. यह ऐप्लिकेशन इन सुविधाओं के साथ काम करता है:

  • मल्टी-विंडो: स्प्लिट-स्क्रीन या फ़्री-फ़ॉर्म मोड में किसी दूसरे ऐप्लिकेशन के साथ चलाने की बुनियादी सुविधा. यह Cahier में नोट लेते समय, किसी वेब पेज का रेफ़रंस देने जैसे कामों के लिए ज़रूरी है.
  • एक से ज़्यादा इंस्टेंस: इस सुविधा की मदद से, एक साथ कई काम किए जा सकते हैं. Cahier की मदद से, उपयोगकर्ता ऐप्लिकेशन की कई अलग-अलग विंडो एक साथ खोल सकते हैं. कल्पना करें कि आपको दो अलग-अलग नोट की तुलना करनी है या एक विंडो में टेक्स्ट नोट का रेफ़रंस देते हुए, दूसरी विंडो में कोई ड्राइंग बनानी है. Cahier, इन अलग-अलग इंस्टेंस को मैनेज करने का तरीका दिखाता है. हर इंस्टेंस की अपनी स्थिति होती है. इससे आपका ऐप्लिकेशन एक शक्तिशाली और कई तरह के काम करने वाला टूल बन जाता है.
  • डेस्कटॉप विंडोइंग: किसी बाहरी डिसप्ले से कनेक्ट करने पर, Android का डेस्कटॉप मोड, टैबलेट या फ़ोल्ड किए जा सकने वाले डिवाइस को वर्कस्टेशन में बदल देता है. Cahier को अडैप्टिव यूज़र इंटरफ़ेस (यूआई) के साथ बनाया गया है. साथ ही, यह एक से ज़्यादा इंस्टेंस की सुविधा के साथ काम करता है. इसलिए, यह ऐप्लिकेशन इस एनवायरमेंट में बहुत अच्छी तरह से काम करता है. उपयोगकर्ता, Cahier की कई विंडो खोल सकते हैं, उनका साइज़ बदल सकते हैं, और उन्हें अपनी पसंद के मुताबिक व्यवस्थित कर सकते हैं. ऐसा पारंपरिक डेस्कटॉप की तरह ही किया जा सकता है. इससे, ऐसे जटिल वर्कफ़्लो को पूरा किया जा सकता है जिन्हें पहले मोबाइल डिवाइसों पर पूरा नहीं किया जा सकता था.
cahier-desktop-windowing.webp

Pixel Tablet पर डेस्कटॉप विंडो मोड में चल रहा Cahier

हमने Cahier में इन सुविधाओं को इस तरह लागू किया है:

मल्टी-इंस्टेंस की सुविधा चालू करने के लिए, हमें सिस्टम को यह बताना था कि ऐप्लिकेशन को एक से ज़्यादा बार लॉन्च किया जा सकता है. इसके लिए, हमें AndroidManifest में MainActivity के एलान में PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI प्रॉपर्टी जोड़नी थी:

<activity

    android:name="com.example.cahier.MainActivity"

    android:exported="true"

    android:label="@string/app_name"

    android:theme="@style/Theme.MyApplication"

    android:showWhenLocked="true"

    android:turnScreenOn="true"

    android:resizeableActivity="true"

    android:launchMode="singleInstancePerTask">


    <property

        android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"

        android:value="true"/>

    ...

</activity>

इसके बाद, हमने ऐप्लिकेशन का नया इंस्टेंस लॉन्च करने के लिए लॉजिक लागू किया. CahierHomeScreen.kt में, जब कोई उपयोगकर्ता किसी नोट को नई विंडो में खोलने का विकल्प चुनता है, तो हम कुछ खास फ़्लैग के साथ एक नया इंटेंट बनाते हैं. ये फ़्लैग, सिस्टम को नई गतिविधि लॉन्च करने का तरीका बताते हैं. FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_MULTIPLE_TASK, और FLAG_ACTIVITY_LAUNCH_ADJACENT को एक साथ दबाने पर, नोट एक नई विंडो में खुलता है. यह विंडो, मौजूदा विंडो के साथ ही खुलती है.

fun openNewWindow(activity: Activity?, note: Note) {

    val intent = Intent(activity, MainActivity::class.java)

    intent.putExtra(AppArgs.NOTE_TYPE_KEY, note.type)

    intent.putExtra(AppArgs.NOTE_ID_KEY, note.id)

    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or

        Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT


    activity?.startActivity(intent)

}

मल्टी-विंडो मोड के लिए, हमें सिस्टम को यह बताना था कि ऐप्लिकेशन का साइज़ बदला जा सकता है. इसके लिए, हमने मेनिफ़ेस्ट के <activity> या <application> एलिमेंट को सेट किया.

<activity

    android:name="com.example.cahier.MainActivity"

    android:resizeableActivity="true"

    ...>

</activity>

यूज़र इंटरफ़ेस (यूआई) को Material 3 अडैप्टिव लाइब्रेरी की मदद से बनाया गया है. इससे, यह मल्टी-विंडो के अलग-अलग मोड में आसानी से अडैप्ट हो जाता है. जैसे, Android का स्प्लिट स्क्रीन मोड. 

उपयोगकर्ता अनुभव को बेहतर बनाने के लिए, हमने ड्रैग और ड्रॉप करने की सुविधा जोड़ी है. हमने Cahier में इसे कैसे लागू किया है, यह नीचे देखें.

खींचना और छोड़ना

कोई भी ऐप्लिकेशन, तब तक पूरी तरह से काम नहीं कर सकता, जब तक वह डिवाइस के अन्य ऐप्लिकेशन के साथ आसानी से इंटरैक्ट न करे. खींचें और छोड़ें की सुविधा, इस इंटरैक्शन का मुख्य हिस्सा है. खास तौर पर, बड़ी स्क्रीन पर जहां उपयोगकर्ता अक्सर कई ऐप्लिकेशन विंडो पर काम करते हैं. Cahier में इस सुविधा का पूरा इस्तेमाल किया गया है. इसमें कॉन्टेंट जोड़ने और शेयर करने के लिए, खींचें और छोड़ें वाली सुविधा को लागू किया गया है.

  • आसानी से इंपोर्ट करना: उपयोगकर्ता, वेब ब्राउज़र, फ़ोटो गैलरी या फ़ाइल मैनेजर जैसे अन्य ऐप्लिकेशन से इमेज को खींचकर, सीधे नोट कैनवस पर छोड़ सकते हैं. इसके लिए, Cahier dragAndDropTarget मॉडिफ़ायर का इस्तेमाल करता है. इससे ड्रॉप ज़ोन तय किया जाता है, image/* जैसे काम करने वाले कॉन्टेंट की जांच की जाती है, और आने वाले यूआरआई को प्रोसेस किया जाता है.
  • आसानी से शेयर करना: Cahier में मौजूद कॉन्टेंट को, अन्य ऐप्लिकेशन के कॉन्टेंट की तरह ही आसानी से शेयर किया जा सकता है. उपयोगकर्ता, टेक्स्ट नोट में मौजूद किसी इमेज को दबाकर रख सकते हैं. इसके अलावा, वे ड्रॉइंग नोट और इमेज कंपोज़िट के पूरे कैनवस को दबाकर रख सकते हैं. इसके बाद, वे इसे खींचकर किसी दूसरे ऐप्लिकेशन में छोड़ सकते हैं.

तकनीकी जानकारी: ड्रॉइंग कैनवस से खींचकर ले जाना

ड्राइंग कैनवस पर ड्रैग जेस्चर लागू करना एक मुश्किल काम है. हमारे DrawingSurface में, लाइव ड्रॉइंग इनपुट (Ink API का InProgressStrokes) को हैंडल करने वाले कंपोज़ेबल और ड्रैग करने की सुविधा शुरू करने के लिए, लंबे समय तक दबाकर रखने के जेस्चर का पता लगाने वाला Box, सिबलिंग कंपोज़ेबल हैं.

डिफ़ॉल्ट रूप से, Jetpack Compose का पॉइंटर इनपुट सिस्टम इस तरह से डिज़ाइन किया गया है कि इवेंट सिर्फ़ एक सिबलिंग कंपोज़ेबल को मिलता है. यह कंपोज़ेबल, टच लोकेशन के हिसाब से डिक्लेरेशन ऑर्डर में पहला होता है. Cahier के मामले में, हम चाहते हैं कि ड्रैग-एंड-ड्रॉप इनपुट हैंडलिंग लॉजिक को चलाने का मौका मिले. साथ ही, InProgressStrokes कंपोज़ेबल के सभी इस्तेमाल न किए गए इनपुट को ड्राइंग के लिए इस्तेमाल करने और फिर उस इनपुट का इस्तेमाल करने से पहले, वह इनपुट का इस्तेमाल कर सके. अगर हम चीज़ों को सही क्रम में व्यवस्थित नहीं करते हैं, तो हमारा Box, खींचकर छोड़ने की सुविधा शुरू करने के लिए, दबाकर रखने के जेस्चर का पता नहीं लगा पाएगा. इसके अलावा, InProgressStrokes को ड्रॉ करने के लिए इनपुट नहीं मिलेगा.

इस समस्या को हल करने के लिए, हमने एक कस्टम pointerInputWithSiblingFallthrough मॉडिफ़ायर बनाया. साथ ही, हमने कंपोज़ेबल कोड में InProgressStrokes से पहले, उस मॉडिफ़ायर का इस्तेमाल करके Box को रखा. यह यूटिलिटी, स्टैंडर्ड pointerInput सिस्टम के चारों ओर एक थिन रैपर है. हालांकि, इसमें एक ज़रूरी बदलाव किया गया है: यह sharePointerInputWithSiblings() फ़ंक्शन को ओवरराइड करके true दिखाता है. इससे Compose फ़्रेमवर्क को यह निर्देश मिलता है कि वह पॉइंटर इवेंट को, इस्तेमाल किए जाने के बाद भी सिबलिंग कंपोज़ेबल तक पहुंचने दे.

internal fun Modifier.pointerInputWithSiblingFallthrough(

    pointerInputEventHandler: PointerInputEventHandler

) = this then PointerInputSiblingFallthroughElement(pointerInputEventHandler)


private class PointerInputSiblingFallthroughModifierNode(

    pointerInputEventHandler: PointerInputEventHandler

) : PointerInputModifierNode, DelegatingNode() {


    var pointerInputEventHandler: PointerInputEventHandler

        get() = delegateNode.pointerInputEventHandler

        set(value) {

            delegateNode.pointerInputEventHandler = value

        }


    val delegateNode = delegate(

        SuspendingPointerInputModifierNode(pointerInputEventHandler)

    )


    override fun onPointerEvent(

        pointerEvent: PointerEvent,

        pass: PointerEventPass,

        bounds: IntSize

    ) {

        delegateNode.onPointerEvent(pointerEvent, pass, bounds)

    }


    override fun onCancelPointerInput() {

        delegateNode.onCancelPointerInput()

    }


    override fun sharePointerInputWithSiblings() = true

}


private data class PointerInputSiblingFallthroughElement(

    val pointerInputEventHandler: PointerInputEventHandler

) : ModifierNodeElement<PointerInputSiblingFallthroughModifierNode>() {


    override fun create() = PointerInputSiblingFallthroughModifierNode(pointerInputEventHandler)


    override fun update(node: PointerInputSiblingFallthroughModifierNode) {

        node.pointerInputEventHandler = pointerInputEventHandler

    }


    override fun InspectorInfo.inspectableProperties() {

        name = "pointerInputWithSiblingFallthrough"

        properties["pointerInputEventHandler"] = pointerInputEventHandler

    }

}

DrawingSurface में इसका इस्तेमाल इस तरह किया जाता है:

Box(

    modifier = Modifier

        .fillMaxSize()

        // Our custom modifier enables this gesture to coexist with the drawing input.

        .pointerInputWithSiblingFallthrough {

            detectDragGesturesAfterLongPress(

                onDragStart = { onStartDrag() },

                onDrag = { _, _ -> /* consume drag events */ },

                onDragEnd = { /* No action needed */ }

            )

        }

) 

// The Ink API's composable for live drawing sits here as a sibling.

InProgressStrokes(...)

इस सुविधा के चालू होने पर, सिस्टम एक साथ ड्राइंग स्ट्रोक और लंबे समय तक दबाकर खींचने के जेस्चर का सही तरीके से पता लगाता है. ड्रैग शुरू होने के बाद, हम FileProvider के साथ शेयर किया जा सकने वाला content:// यूआरआई बनाते हैं. इसके बाद, view.startDragAndDrop() का इस्तेमाल करके, यूआरआई को सिस्टम के खींचें और छोड़ें फ़्रेमवर्क में पास करते हैं. इस समाधान से, बेहतर और आसान उपयोगकर्ता अनुभव मिलता है. साथ ही, यह पता चलता है कि लेयर वाले यूज़र इंटरफ़ेस में, हाथ के जेस्चर से जुड़ी मुश्किल समस्याओं को कैसे हल किया जा सकता है.

आधुनिक वास्तुकला के हिसाब से बनाया गया

Cahier, कुछ खास एपीआई के अलावा, अच्छी क्वालिटी वाले अडैप्टिव ऐप्लिकेशन बनाने के लिए ज़रूरी आर्किटेक्चरल पैटर्न भी दिखाता है.

प्रज़ेंटेशन लेयर: Jetpack Compose और अडैप्टेबिलिटी

प्रज़ेंटेशन लेयर को पूरी तरह से Jetpack Compose की मदद से बनाया गया है. जैसा कि बताया गया है, Cahier, यूज़र इंटरफ़ेस (यूआई) को अडैप्टिव बनाने के लिए material3-adaptive लाइब्रेरी का इस्तेमाल करता है. स्टेट मैनेजमेंट, एकतरफ़ा डेटा फ़्लो (यूडीएफ़) के पैटर्न का पालन करता है. इसमें ViewModel इंस्टेंस का इस्तेमाल डेटा कंटेनर के तौर पर किया जाता है. ये कंटेनर, नोट की जानकारी और यूज़र इंटरफ़ेस (यूआई) की स्थिति को सेव रखते हैं.

डेटा लेयर: रिपॉज़िटरी और Room

डेटा लेयर के लिए, Cahier सभी डेटा ऑपरेशन को एब्स्ट्रैक्ट करने के लिए NoteRepository इंटरफ़ेस का इस्तेमाल करता है. इस डिज़ाइन की वजह से, ऐप्लिकेशन को स्थानीय डेटा सोर्स (Room) और आने वाले समय में इस्तेमाल होने वाले रिमोट बैकएंड के बीच आसानी से स्विच करने की सुविधा मिलती है. नोट में बदलाव करने जैसी कार्रवाई के लिए डेटा फ़्लो इस तरह होता है:

  1. Jetpack Compose यूज़र इंटरफ़ेस (यूआई), ViewModel में मौजूद किसी तरीके को ट्रिगर करता है.
  2. ViewModel, NoteRepository से नोट फ़ेच करता है, लॉजिक को हैंडल करता है, और अपडेट किए गए नोट को वापस रिपॉज़िटरी में भेजता है.
  3. NoteRepository, अपडेट को Room डेटाबेस में सेव करता है.

इनपुट के लिए बेहतर सहायता

किसी ऐप्लिकेशन को वाकई में ज़्यादा काम करने में मदद करने वाला ऐप्लिकेशन बनने के लिए, यह ज़रूरी है कि वह अलग-अलग इनपुट मेथड को बिना किसी गड़बड़ी के इस्तेमाल कर सके. Cahier को बड़ी स्क्रीन पर इनपुट देने से जुड़े दिशा-निर्देशों के मुताबिक बनाया गया है. इसमें ये सुविधाएं काम करती हैं:

  • स्टाइलस: Ink API के साथ इंटिग्रेशन, हथेली को स्क्रीन पर रखने पर भी स्टाइलस के काम करने की सुविधा, नोट बनाने की सुविधा के लिए रजिस्टर करना, टेक्स्ट फ़ील्ड में स्टाइलस से इनपुट देना, और इमर्सिव मोड.
  • कीबोर्ड: कीबोर्ड के ज़्यादातर सामान्य शॉर्टकट और कॉम्बिनेशन (जैसे, ctrl+क्लिक, meta+क्लिक) के लिए सहायता उपलब्ध है. साथ ही, कीबोर्ड फ़ोकस के बारे में साफ़ तौर पर बताया गया है.
  • माउस और ट्रैकपैड: राइट क्लिक करने और कर्सर घुमाने की सुविधा.

हमारा मुख्य फ़ोकस, कीबोर्ड, माउस, और ट्रैकपैड के साथ बेहतर तरीके से इंटरैक्ट करने की सुविधा को बेहतर बनाना है. 

आज ही शुरू करें

हमें उम्मीद है कि Cahier आपके अगले बेहतरीन ऐप्लिकेशन को लॉन्च करने में आपकी मदद करेगा. हमने इसे एक व्यापक, ओपन सोर्स संसाधन के तौर पर बनाया है. इससे यह पता चलता है कि अडैप्टिव यूज़र इंटरफ़ेस (यूआई), Ink और नोट की भूमिका जैसे पावरफ़ुल एपीआई, और मॉडर्न, अडैप्टिव आर्किटेक्चर को कैसे जोड़ा जाए.

क्या आप शुरू करने के लिए तैयार हैं?

  • कोड एक्सप्लोर करें: Cahier के कोड बेस को एक्सप्लोर करने और डिज़ाइन के सिद्धांतों को ऐक्शन में देखने के लिए, हमारी GitHub रिपॉज़िटरी पर जाएं.
  • अपनी ज़रूरत के हिसाब से बनाएं: Cahier का इस्तेमाल, नोट लेने, दस्तावेज़ मार्कअप करने या क्रिएटिव ऐप्लिकेशन के लिए करें.
  • योगदान दें: हम आपके योगदान का स्वागत करते हैं! Android डेवलपर कम्यूनिटी के लिए, Cahier को और भी बेहतर संसाधन बनाने में हमारी मदद करें.

डेवलपर के लिए बनी आधिकारिक गाइड देखें. साथ ही, आज ही अगली जनरेशन का प्रॉडक्टिविटी और क्रिएटिविटी ऐप्लिकेशन बनाना शुरू करें. हमें यह देखने का बेसब्री से इंतज़ार है कि आप किस तरह का कॉन्टेंट बनाते हैं!

लेखक:
पढ़ना जारी रखें