برنامه نویسی

کمی بیشتر مدیریت چرخه زندگی

Summarize this content to 400 words in Persian Lang

کمی بیشتر مدیریت چرخه زندگی

چارچوب کمی بیشتر برای Flutter Framework باعث ایجاد برنامه های بهتر می شود

به‌عنوان بخشی از مجموعه «بیشتر کوچک»، این مقاله رویدادهای چرخه زندگی را که باید هنگام اجرای برنامه در نظر گرفته شوند، مرور می‌کند. رویدادهایی که هنگام استفاده از آن به راحتی در دسترس شما قرار می گیرند [Fluttery Framework] بسته بندی

چرخه عمر برنامه iOS

چرخه عمر برنامه اندروید

مانند همتایان iOS و Android خود (به بالا مراجعه کنید)، Flutter StatefulWidgets چرخه زندگی خاص خود را دارد. در زیر یک تصویر گرافیکی از آن چرخه زندگی است که در حال حاضر درک شده است. فلش ها را دنبال کنید، و در صورت وقوع شرایط خاصی، “توالی فراخوانی تابع” را دنبال می کنید. با استفاده از Framework Fluttery، شی State شما همیشه یک تابع متناظر برای رسیدگی به چنین رویدادهایی خواهد داشت – به هر حال تا جایی که می تواند.

ببینید، Flutter یک راه حل بین پلتفرمی است – موتور Flutter بر روی یک سیستم عامل کاملاً متفاوت بسته به دستگاه کار می کند. به این ترتیب، در مورد فلاتر (که در تصویر با خط نقطه چین مشخص می شود) دو چرخه زندگی جداگانه درگیر است. متأسفانه، تا لحظه نگارش این مقاله، این دو چرخه زندگی به هیچ وجه یکدیگر را تصدیق نمی کنند.

داستان های دیگر از گرگ پری

به عنوان مثال، Flutter یک StatefulWidget را فراخوانی نمی کند از کار انداختن() و در معرض قرار دادن() هر زمان که کاربر برنامه شما را با حرکات دست “غیر متمرکز” کند کار می کند – فقط به زودی آن را خاتمه می دهد. برای آن دسته از توسعه دهندگانی که به طور خاص روی پلتفرم های موبایل کار می کنند، این موضوع به یک مشکل تبدیل شده است.

با این حال، با Fluttery Framework، تلاشی برای فراخوانی صورت گرفته است از کار انداختن() و در معرض قرار دادن() عملکرد همه StatefulWidgets برنامه هر زمان که چنین سناریویی رخ می دهد (نمایش دوم را در زیر ببینید). متأسفانه، از زمان نوشتن این مقاله، به سیستم عامل خاصی مربوط می شود که آیا آنها فراخوانی می شوند یا نه:”AppLifeCycleState.detached هنگامی که برنامه به سرعت بسته می شود فراخوانی نمی شود”

state_extended.dart

ویدیوی زیر دارای نمونه برنامه است، widgetsbinding_observer_example، در حال اجرا بر روی شبیه ساز تلفن همراه. این برنامه پر شده است چاپ() به گونه‌ای عمل می‌کند که وقتی رویدادهای خاص تحریک می‌شوند و در کدام حالت شیء هستند، عمل می‌کند. در این ویدیو، برنامه فوراً فوکوس خود را از دست می‌دهد، اما سپس به پیش‌زمینه برمی‌گردد – فقط قبل از پایان یافتن، دوباره تمرکز خود را از دست می‌دهد. بدون دخالت، آن صفحه نمایش است از کار انداختن() و در معرض قرار دادن() توابع هرگز فراخوانی نمی شدند. این گرافیک مجدداً در زیر برای مقایسه با مجاور ارائه شده است چاپ() فراخوانی تابع.

قانون شماره 2 را در نظر داشته باشید

صرف نظر از پلتفرم، به یاد داشته باشید که پایگاه داده و سایر منابع مهم زمانی را در **hiddenAppLifeCycleState ببندید() روش فقط برای باز کردن دوباره آنها در روش ** resumeAppLifeCycleState()، اگر و زمانی که کاربر به برنامه شما بازگردد.

این می تواند واقعاً پیچیده باشد، اما چارچوب Fluttery برای کمک به شما اینجاست.

یک مثال سریع دیگر در ویدیوی زیر نشان داده شده است. صفحه 1 و صفحه 2 دو ویجت Stateful هستند که یکی پس از دیگری نامیده می شوند. سپس کاربر از صفحه 2 به صفحه 1 برمی گردد. باز هم، برنامه مثال با تعداد زیادش چاپتوابع () تمام رویدادهایی را که رخ می دهند را شرح می دهد (به زیر مراجعه کنید). در این حالت، می توانید ببینید زمانی که Page2 بسته شد، توابع، از کار انداختن() و در معرض قرار دادن()، پشت سر هم نامیده می شوند.

غیرفعال کردن بهتر از دور انداختن است

این را به خاطر بسپارید: شما هیچ ایده ای نخواهید داشت که یک State شیء است در معرض قرار دادن() نامیده می شود – اگر همیشه. این عملکرد توسط موتور فلاتر به عنوان بخشی از فرآیند “جمع آوری زباله” آن فراخوانی می شود. این به صلاحدید موتور است که در معرض قرار دادن() تابع فراخوانی می شود (یا هرگز تحت محدودیت های حافظه خاصی فراخوانی نمی شود)، و بنابراین، اگر StatefulWidget های شما دارای منابع مهم زمانی هستند که آزاد می شوند و مانند آن، انجام این کار در آنها قابل اطمینان تر است. از کار انداختن() توابع و نه در آنها در معرض قرار دادن() کارکرد.

قانون شماره 1 را در نظر داشته باشید

صرف نظر از پلتفرم، اگر StatefulWidget در حال بسته شدن دیگر نیازی به آن ندارد، به یاد داشته باشید که هر پایگاه داده و منابع مهم زمانی را در **غیرفعال کردن آن ببندید.() روش فقط برای باز کردن دوباره آنها در روش خود، **فعال کنید()، اگر StatefulWidget در حال اجرا بسته نشده باشد اما در عوض در درخت ویجت جابجا شده باشد (مثلاً ترتیب مجدد موارد در ویجت ListView).

سری رویدادها

بیایید به سرعت فراخوانی‌های توابع رویداد فهرست شده در بالا را مرور کنیم و آنچه را که نشان می‌دهند را پیشنهاد کنیم. همانطور که می دانید، هنگامی که یک شیء State برای اولین بار ایجاد می شود، این دو تابع زیر هستند که فراخوانی می شوند. اولین شیء حالت نامیده می شود، _AppState.

چارچوب Fluttery از وجود روتر در این برنامه مثال “آگاه است” و بنابراین صفحه “خانه” با شی State خود، _Page1State، راه اندازی شده است و به زودی با آن تماس خواهد گرفت initState() تابع، اما نه قبل از تابع رویداد آن، didPush()، firsr نامیده می شود. این به شما امکان می دهد تا کد را اجرا کنید “زمانی که StatefulWidget به تازگی توسط یک روتر باز می شود.”

دو بعدی چاپ() توابع در زیر نمایش داده شده است. آنها به ما می گویند که “صفحه 1” اکنون با شمارش صفر نمایش داده می شود.

از آنجایی که این برنامه بر روی یک شبیه ساز تلفن همراه اجرا می شد، رنگ آمیزی و اندازه رابط کاربری برنامه باعث می شود didChangeMetrics() در دو StatefulWidget که تا کنون برنامه را تشکیل می دهند. توجه داشته باشید که چگونه آنها را به ترتیبی که نمونه‌سازی کردند – با کمک Fluttery Framework فراخوانی می‌شوند.

خط بعدی به صفحه 1 می گوید که صفحه بعدی که قرار است نمایش داده شود انتخاب شده است در حالی که خط دوم به صفحه 2 می گوید که به دلیل روتر ایجاد شده است. توجه داشته باشید، برای دستیابی به این هدف، امکان اختراع مجدد چرخ وجود ندارد. Fluttery فقط آنچه را که قبلاً در Flutter وجود دارد برای یادداشت این رویدادها اجرا می کند.

سه خط بعدی به شما می گوید که «صفحه 2» اکنون با شمارش صفر نمایش داده می شود.

در اسکرین شات بعدی زیر، هر دو صفحه اول و صفحه دوم هنگامی که کاربر به صفحه 1 بازگشته است مطلع می شوند. چیزهای عالی!

در نتیجه، صفحه 2 در شرف حذف از حافظه است. بنابراین، دو خط بعدی ظاهر می شود. دوباره، از کار انداختن() مکان بهتری برای “تمیز کردن چیزها” قبل از بازگشت به صفحه قبلی است. را در معرض قرار دادن() بلافاصله بعد از فراخوانی تابع از کار انداختن() صادقانه بگویم. تحت شرایط مختلف خارج از کنترل شما، به همین راحتی هرگز نمی توان آن را فراخوانی کرد.

زمان همه چیز است

با بازی کردن با برنامه مثال، متوجه خواهید شد که صفحه 5 دارای یک تایمر است که “جفت کلمات” را نشان می دهد که در آزمایشگاه کد وب سایت Flutter به نام “First Flutter app” معرفی شده است. زیر را ببینید.

نگاه کنید که شی تایمر چگونه مدیریت می شود. در صورت لزوم روشن و خاموش می شود. شما ابزار آماده ای دارید تا با استفاده از Fluttery تمام منابع در حال اجرا خود را به طور موثر و کارآمد مدیریت کنید. حرکت از صفحه 5 به صفحات بعدی بدون پرداختن به شی تایمر، یا یک جریان فعال یا برخی فرآیندهای آزاد در حال اجرا دیگر، فقط شلخته است! به یک معنا، شما فقط یک نشت حافظه را در غیر این صورت پیاده سازی کرده اید!

اسکرین شات دوم همان کدی است که هنگام جابجایی از صفحه 5 به صفحه 6 و به عقب خوانده می شود. با فلش قرمز اول مشخص شده تایمر خاموش است در حالی که فلش قرمز دوم روشن شدن مجدد تایمر را مشخص می کند. اولین اسکرین شات بیانیه های چاپی را فهرست می کند که عملکردهای رویداد درگیر در ویدیو را منتقل می کند – آخرین قسمت آن که بسته شدن برنامه را نشان می دهد دوباره در ادامه در زیر نمایش داده می شود.

می توانید ببینید که چگونه “رویدادهای سیستم عامل” توسط چارچوب Fluttery پوشش داده می شود. می توانید این را با مقایسه بیانیه های چاپی با نمودار چرخه عمر زیر مشاهده کنید. توجه داشته باشید، Fluttery بر روی یک شبیه ساز تلفن که روی لپ تاپ اجرا می شود، حتی محدودیت حافظه را که با فراخوانی عملکرد ایجاد می شود، تشخیص می دهد. didHaveMemoryPressure().

نگاه کنید که چگونه همه رویدادهای سیستم عامل در همه اشیاء حالتی که در حال حاضر در برنامه اجرا می شوند، به نوبه خود و به ترتیبی که نمونه سازی شده اند، فعال می شوند. دستگاه میزبان چیزی است، و همه اشیاء State در حال اجرا باید از آن آگاه باشند.

برنامه نمونه، [widgetsbinding_observer_example]، دارای نه صفحه نمایش جداگانه است که یکی پس از دیگری فراخوانی می شوند. توجه داشته باشید که چگونه اشیاء State و کنترل‌کننده‌های همراه آن‌ها (اجزای منطق تجاری مانند معماری BLoC) به ترتیبی که نمونه‌سازی شده‌اند فعال می‌شوند.

برنامه نمونه را دانلود کنید، [widgetsbinding_observer_example]و ببینید که Fluttery چگونه برای شما کار می کند تا برنامه Flutter خود را از دستگاه پلتفرمی که روی آن اجرا می شود آگاه تر کنید. اگر برنامه بهتری می خواهید این یک ضرورت است.

به سلامتی.

← سری “کمی بیشتر”.

← داستان های دیگر از گرگ پری

کمی بیشتر مدیریت چرخه زندگی

چارچوب کمی بیشتر برای Flutter Framework باعث ایجاد برنامه های بهتر می شود

به‌عنوان بخشی از مجموعه «بیشتر کوچک»، این مقاله رویدادهای چرخه زندگی را که باید هنگام اجرای برنامه در نظر گرفته شوند، مرور می‌کند. رویدادهایی که هنگام استفاده از آن به راحتی در دسترس شما قرار می گیرند [Fluttery Framework] بسته بندی

چرخه عمر برنامه iOS

1%2A9zhAz4i61IKHr F0 5Mrog

چرخه عمر برنامه اندروید

مانند همتایان iOS و Android خود (به بالا مراجعه کنید)، Flutter StatefulWidgets چرخه زندگی خاص خود را دارد. در زیر یک تصویر گرافیکی از آن چرخه زندگی است که در حال حاضر درک شده است. فلش ها را دنبال کنید، و در صورت وقوع شرایط خاصی، “توالی فراخوانی تابع” را دنبال می کنید. با استفاده از Framework Fluttery، شی State شما همیشه یک تابع متناظر برای رسیدگی به چنین رویدادهایی خواهد داشت – به هر حال تا جایی که می تواند.

ببینید، Flutter یک راه حل بین پلتفرمی است – موتور Flutter بر روی یک سیستم عامل کاملاً متفاوت بسته به دستگاه کار می کند. به این ترتیب، در مورد فلاتر (که در تصویر با خط نقطه چین مشخص می شود) دو چرخه زندگی جداگانه درگیر است. متأسفانه، تا لحظه نگارش این مقاله، این دو چرخه زندگی به هیچ وجه یکدیگر را تصدیق نمی کنند.

1%2AO

داستان های دیگر از گرگ پری

به عنوان مثال، Flutter یک StatefulWidget را فراخوانی نمی کند از کار انداختن() و در معرض قرار دادن() هر زمان که کاربر برنامه شما را با حرکات دست “غیر متمرکز” کند کار می کند – فقط به زودی آن را خاتمه می دهد. برای آن دسته از توسعه دهندگانی که به طور خاص روی پلتفرم های موبایل کار می کنند، این موضوع به یک مشکل تبدیل شده است.

با این حال، با Fluttery Framework، تلاشی برای فراخوانی صورت گرفته است از کار انداختن() و در معرض قرار دادن() عملکرد همه StatefulWidgets برنامه هر زمان که چنین سناریویی رخ می دهد (نمایش دوم را در زیر ببینید). متأسفانه، از زمان نوشتن این مقاله، به سیستم عامل خاصی مربوط می شود که آیا آنها فراخوانی می شوند یا نه:
“AppLifeCycleState.detached هنگامی که برنامه به سرعت بسته می شود فراخوانی نمی شود”

1%2AVfR6rVphbn3o2oSgN gd2w

1%2ANRG1UsuZAk7ANHfR1gkGDg

state_extended.dart

ویدیوی زیر دارای نمونه برنامه است، widgetsbinding_observer_example، در حال اجرا بر روی شبیه ساز تلفن همراه. این برنامه پر شده است چاپ() به گونه‌ای عمل می‌کند که وقتی رویدادهای خاص تحریک می‌شوند و در کدام حالت شیء هستند، عمل می‌کند. در این ویدیو، برنامه فوراً فوکوس خود را از دست می‌دهد، اما سپس به پیش‌زمینه برمی‌گردد – فقط قبل از پایان یافتن، دوباره تمرکز خود را از دست می‌دهد. بدون دخالت، آن صفحه نمایش است از کار انداختن() و در معرض قرار دادن() توابع هرگز فراخوانی نمی شدند. این گرافیک مجدداً در زیر برای مقایسه با مجاور ارائه شده است چاپ() فراخوانی تابع.

1%2AWDXprTseCLv jPhsk2sr8Q

1%2AO

قانون شماره 2 را در نظر داشته باشید

صرف نظر از پلتفرم، به یاد داشته باشید که پایگاه داده و سایر منابع مهم زمانی را در **hiddenAppLifeCycleState ببندید() روش فقط برای باز کردن دوباره آنها در روش ** resumeAppLifeCycleState()، اگر و زمانی که کاربر به برنامه شما بازگردد.

این می تواند واقعاً پیچیده باشد، اما چارچوب Fluttery برای کمک به شما اینجاست.

یک مثال سریع دیگر در ویدیوی زیر نشان داده شده است. صفحه 1 و صفحه 2 دو ویجت Stateful هستند که یکی پس از دیگری نامیده می شوند. سپس کاربر از صفحه 2 به صفحه 1 برمی گردد. باز هم، برنامه مثال با تعداد زیادش چاپتوابع () تمام رویدادهایی را که رخ می دهند را شرح می دهد (به زیر مراجعه کنید). در این حالت، می توانید ببینید زمانی که Page2 بسته شد، توابع، از کار انداختن() و در معرض قرار دادن()، پشت سر هم نامیده می شوند.

1%2A6gatgfVyQhfBmZbUQkpE7A

غیرفعال کردن بهتر از دور انداختن است

این را به خاطر بسپارید: شما هیچ ایده ای نخواهید داشت که یک State شیء است در معرض قرار دادن() نامیده می شود – اگر همیشه. این عملکرد توسط موتور فلاتر به عنوان بخشی از فرآیند “جمع آوری زباله” آن فراخوانی می شود. این به صلاحدید موتور است که در معرض قرار دادن() تابع فراخوانی می شود (یا هرگز تحت محدودیت های حافظه خاصی فراخوانی نمی شود)، و بنابراین، اگر StatefulWidget های شما دارای منابع مهم زمانی هستند که آزاد می شوند و مانند آن، انجام این کار در آنها قابل اطمینان تر است. از کار انداختن() توابع و نه در آنها در معرض قرار دادن() کارکرد.

قانون شماره 1 را در نظر داشته باشید

صرف نظر از پلتفرم، اگر StatefulWidget در حال بسته شدن دیگر نیازی به آن ندارد، به یاد داشته باشید که هر پایگاه داده و منابع مهم زمانی را در **غیرفعال کردن آن ببندید.() روش فقط برای باز کردن دوباره آنها در روش خود، **فعال کنید()، اگر StatefulWidget در حال اجرا بسته نشده باشد اما در عوض در درخت ویجت جابجا شده باشد (مثلاً ترتیب مجدد موارد در ویجت ListView).

سری رویدادها

بیایید به سرعت فراخوانی‌های توابع رویداد فهرست شده در بالا را مرور کنیم و آنچه را که نشان می‌دهند را پیشنهاد کنیم. همانطور که می دانید، هنگامی که یک شیء State برای اولین بار ایجاد می شود، این دو تابع زیر هستند که فراخوانی می شوند. اولین شیء حالت نامیده می شود، _AppState.

1%2AXeHXqgaNCkUMMcCgwXL 9w

چارچوب Fluttery از وجود روتر در این برنامه مثال “آگاه است” و بنابراین صفحه “خانه” با شی State خود، _Page1State، راه اندازی شده است و به زودی با آن تماس خواهد گرفت initState() تابع، اما نه قبل از تابع رویداد آن، didPush()، firsr نامیده می شود. این به شما امکان می دهد تا کد را اجرا کنید “زمانی که StatefulWidget به تازگی توسط یک روتر باز می شود.”

دو بعدی چاپ() توابع در زیر نمایش داده شده است. آنها به ما می گویند که “صفحه 1” اکنون با شمارش صفر نمایش داده می شود.

1%2AVtyjFs95RF7Glwmfgm itQ

از آنجایی که این برنامه بر روی یک شبیه ساز تلفن همراه اجرا می شد، رنگ آمیزی و اندازه رابط کاربری برنامه باعث می شود didChangeMetrics() در دو StatefulWidget که تا کنون برنامه را تشکیل می دهند. توجه داشته باشید که چگونه آنها را به ترتیبی که نمونه‌سازی کردند – با کمک Fluttery Framework فراخوانی می‌شوند.

1%2Ao HJ6u9 NLaZe3gWh0G4 Q

خط بعدی به صفحه 1 می گوید که صفحه بعدی که قرار است نمایش داده شود انتخاب شده است در حالی که خط دوم به صفحه 2 می گوید که به دلیل روتر ایجاد شده است. توجه داشته باشید، برای دستیابی به این هدف، امکان اختراع مجدد چرخ وجود ندارد. Fluttery فقط آنچه را که قبلاً در Flutter وجود دارد برای یادداشت این رویدادها اجرا می کند.

1%2A RN7Ri8EUPQo wHgyJzTw

سه خط بعدی به شما می گوید که «صفحه 2» اکنون با شمارش صفر نمایش داده می شود.

1%2Aij iqU0VReya4sDkKAVz5Q

در اسکرین شات بعدی زیر، هر دو صفحه اول و صفحه دوم هنگامی که کاربر به صفحه 1 بازگشته است مطلع می شوند. چیزهای عالی!

1%2AVqTqhmscN3HtuMZo VsIXA

در نتیجه، صفحه 2 در شرف حذف از حافظه است. بنابراین، دو خط بعدی ظاهر می شود. دوباره، از کار انداختن() مکان بهتری برای “تمیز کردن چیزها” قبل از بازگشت به صفحه قبلی است. را در معرض قرار دادن() بلافاصله بعد از فراخوانی تابع از کار انداختن() صادقانه بگویم. تحت شرایط مختلف خارج از کنترل شما، به همین راحتی هرگز نمی توان آن را فراخوانی کرد.

1%2AgoU8lA JriY7c32XiCK4Fg

زمان همه چیز است

با بازی کردن با برنامه مثال، متوجه خواهید شد که صفحه 5 دارای یک تایمر است که “جفت کلمات” را نشان می دهد که در آزمایشگاه کد وب سایت Flutter به نام “First Flutter app” معرفی شده است. زیر را ببینید.

نگاه کنید که شی تایمر چگونه مدیریت می شود. در صورت لزوم روشن و خاموش می شود. شما ابزار آماده ای دارید تا با استفاده از Fluttery تمام منابع در حال اجرا خود را به طور موثر و کارآمد مدیریت کنید. حرکت از صفحه 5 به صفحات بعدی بدون پرداختن به شی تایمر، یا یک جریان فعال یا برخی فرآیندهای آزاد در حال اجرا دیگر، فقط شلخته است! به یک معنا، شما فقط یک نشت حافظه را در غیر این صورت پیاده سازی کرده اید!

اسکرین شات دوم همان کدی است که هنگام جابجایی از صفحه 5 به صفحه 6 و به عقب خوانده می شود. با فلش قرمز اول مشخص شده تایمر خاموش است در حالی که فلش قرمز دوم روشن شدن مجدد تایمر را مشخص می کند. اولین اسکرین شات بیانیه های چاپی را فهرست می کند که عملکردهای رویداد درگیر در ویدیو را منتقل می کند – آخرین قسمت آن که بسته شدن برنامه را نشان می دهد دوباره در ادامه در زیر نمایش داده می شود.

1%2AU8TAQuC0EOO2 CPBvObvUw

1%2AjMNFvDV6u4zro5ATz 2DMQ

[page_05.dart](https://github.com/Andrious/widgetsbinding_observer_example/blob/master/lib/main/view/screens/page_05.dart#L59)

می توانید ببینید که چگونه “رویدادهای سیستم عامل” توسط چارچوب Fluttery پوشش داده می شود. می توانید این را با مقایسه بیانیه های چاپی با نمودار چرخه عمر زیر مشاهده کنید. توجه داشته باشید، Fluttery بر روی یک شبیه ساز تلفن که روی لپ تاپ اجرا می شود، حتی محدودیت حافظه را که با فراخوانی عملکرد ایجاد می شود، تشخیص می دهد. didHaveMemoryPressure().

نگاه کنید که چگونه همه رویدادهای سیستم عامل در همه اشیاء حالتی که در حال حاضر در برنامه اجرا می شوند، به نوبه خود و به ترتیبی که نمونه سازی شده اند، فعال می شوند. دستگاه میزبان چیزی است، و همه اشیاء State در حال اجرا باید از آن آگاه باشند.

1%2A0w5QyInCXjrcDtrMMDcKTQ

1%2AO

برنامه نمونه، [widgetsbinding_observer_example]، دارای نه صفحه نمایش جداگانه است که یکی پس از دیگری فراخوانی می شوند. توجه داشته باشید که چگونه اشیاء State و کنترل‌کننده‌های همراه آن‌ها (اجزای منطق تجاری مانند معماری BLoC) به ترتیبی که نمونه‌سازی شده‌اند فعال می‌شوند.

1%2AHd534n AcpjIuQnknTSRHQ

1%2AtVZvPdYAiTM YrIAFbJwlA

1%2Af9ClPGJcEVRuFLpi6UM4GQ

1%2An7Nh3 QwdxdpiAgFNqo mg

1%2AUPlHLU frOK7OSHVRJLyhg

برنامه نمونه را دانلود کنید، [widgetsbinding_observer_example]و ببینید که Fluttery چگونه برای شما کار می کند تا برنامه Flutter خود را از دستگاه پلتفرمی که روی آن اجرا می شود آگاه تر کنید. اگر برنامه بهتری می خواهید این یک ضرورت است.

به سلامتی.

← سری “کمی بیشتر”.

← داستان های دیگر از گرگ پری

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا