<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Fatemeh Movassaghpour</title>
        <link>https://virgool.io/feed/@fatemeh_msp</link>
        <description>Android Developer</description>
        <language>fa</language>
        <pubDate>2026-04-15 06:59:44</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/4054/avatar/SS3LFI.png?height=120&amp;width=120</url>
            <title>Fatemeh Movassaghpour</title>
            <link>https://virgool.io/@fatemeh_msp</link>
        </image>

                    <item>
                <title>آمار بازدید پست‌های من در سال ۹۹</title>
                <link>https://virgool.io/@fatemeh_msp/%D8%A2%D9%85%D8%A7%D8%B1-%D8%A8%D8%A7%D8%B2%D8%AF%DB%8C%D8%AF-%D9%BE%D8%B3%D8%AA-%D9%87%D8%A7%DB%8C-%D9%85%D9%86-%D8%AF%D8%B1-%D8%B3%D8%A7%D9%84-%DB%B9%DB%B9-ke6w5gcy0tdk</link>
                <description>در طول تاریخ از اعداد استفاده کردیم تا اغلب داد و ستد کنیم و آن‌چیزی که شمردنی است را بشماریم. برای هر عدد واحد درست کردیم تا عددهای زندگی قاطی نشوند و از اعداد، شفاف‌تر استفاده کنیم؛ مثلا وقتی می‌گوییم ده هزار تومان به پول اشاره داریم و وقتی می‌گوییم ده هزار بلیط به بلیط!روز به روز که در زندگی جلو‌تر رفتیم عددها فرقی نکردند ولی این واحدها بودند که زیاد شدند. واحد کریپتو، واحد اصله درخت، واحد فاصله و …«واحد» یک توافق عمومی است برای شمردن؛ تا همانطور که گفتم شمردن‌ها قاطی نشود. مشاهده افراد دارای ثروت (اجتماعی یا مالی) به من ثابت کرده اینکه چه چیزی را بشماریم از اینکه چطور بشماریم مهم‌تر است. هرکس با واحد خاصی مسائل زندگی را می‌شمارد. اینطور به نظرم آمده که مشخص کردن واحد یعنی مشخص کردن اینکه من در زندگی برای چه چیزهایی ارزش قائلم و می‌خواهم چه چیزهایی را در زندگی بشمارم. https://cdn.virgool.io/annual-report/1399/ykr4zeavqqh5-r15DY.mp4 اعدادی که بدون واحد ثبت کردمبه ویدیویی که ویرگول برایم ساخته که نگاه می‌کنم میبینم که در سال ۹۹، من در مجموع ۱,۲۸۱ کلمه در ویرگول نوشتم و منتشر کردم و مخاطبین، پست‌های من را ۱۵ مرتبه پسندیدند و  ۲ بار هم نظر خود را روی پست‌های من به اشتراک گذاشتند. در سال ۹۹، ۱۶ نفر در ویرگول من را دنبال کردند تا پست‌های بعدیم را بخوانند. این اعداد نشان میدهند من کاری کرده‌ام. هرکدام به واحدی وصل هستند. از خودم می‌پرسم من کدام واحد را شمارش کرده‌ام؟ کدامیک از واحدهای بالا از همه برای من مهم‌تر است؟ ادامه ویدیو را می‌بینم.آمار از اثر بیرونی می‌گویندطبق آمار پست‌های من ۴۸۲ بار خوانده شدند و ۳۸,۶۸۳ ثانیه صرف مطالعه آنها شده است، که با توجه به جمعیتی که در ایران به اینترنت دسترسی دارند، ویرگول به من می‌گوید که توانستم  ۰/۰۰۰۵۳۰۳۴۰ ثانیه، سرانه مطالعه دیجیتال کشور را بالا ببرم.از طرف دیگر ویرگول به من می‌گوید که اگر قرار بود پست‌هایم را چاپ و به دست تک تک خوانندگان برسانم باید ۱,۴۵۴ کاغذ مصرف می‌کردم.آن عددهای کوچک ابتدای ویدیو حالا تبدیل شده‌اند به عددهای بزرگ به اینکه من جلوی مصرف این تعداد کاغذ را گرفتم یا به اینکه من  ۰/۰۰۰۵۳۰۳۴۰ ثانیه، سرانه مطالعه دیجیتال کشور را جابه جا کرده‌ام. واحد این عددها برای من ملموس‌تر است.واحد نوشتن چیست؟همه عددهای بالا و همینطور اثر بیرونی که روی خوانندگان و همینطور در مقیاس بزرگتر طبیعت و جامعه اطرافم گذاشتم اعدادی هستند که من دوستشان دارم و به آنها افتخار می‌کنم. اگر چنین ویدیویی دست شما نیز رسید به شما بابت تک تک اعداد تبریک می‌گویم.اثر هر نوشته تا حدودی معلوم است، اگر بنویسید جلوی قطع درخت را می‌گیرید، به سرانه مطالعه کشور اضافه می‌کنید و خوانندگانی جذب می‌کنید که شما را از طریق نوشته‌هایتان می‌شناسند و …به نظرم می‌رسد که نوشته‌های من و شما واحد ندارند ولی اثر بیرونی دارند.</description>
                <category>Fatemeh Movassaghpour</category>
                <author>Fatemeh Movassaghpour</author>
                <pubDate>Mon, 22 Mar 2021 14:06:59 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش کار با Epoxy در اندروید - قسمت ۲ (کاتلین)</title>
                <link>https://virgool.io/@fatemeh_msp/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-epoxy-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D9%82%D8%B3%D9%85%D8%AA-%DB%B2-%DA%A9%D8%A7%D8%AA%D9%84%DB%8C%D9%86-qivmdebtwidm</link>
                <description>Epoxyاگه قسمت قبلی خونده باشین بریم که قسمت دوم اختصاصی برای کاتلین شروع کنیم و اگر نه حتما اول قسمت اول مطالعه کنید.قسمت اول قبلا هم گفتیم که دو مفهوم epoxy model , epoxy controller توی این لایبری خیلی مهم هست حالا توی کاتلین علاوه بر چیز هایی که قبلا گفتیم میشه از این روش هم اقدام کرد.اول ) Kotlin Model : کافی این کلاس به پروژه اضافه کنیم و model هامون رو از اون extend کنیم :import android.view.View
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import com.airbnb.epoxy.EpoxyModel
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * A pattern for using epoxy models with Kotlin with no annotations or code generation.
 *
 * See [com.airbnb.epoxy.kotlinsample.models.ItemDataClass] for a usage example.
 */
abstract class KotlinModel(
    @LayoutRes private val layoutRes: Int
) : EpoxyModel&lt;View&gt;() {

    private var view: View? = null

    abstract fun bind()

    override fun bind(view: View) {
        this.view = view
        bind()
    }

    override fun unbind(view: View) {
        this.view = null
    }

    override fun getDefaultLayout() = layoutRes

    protected fun &lt;V : View&gt; bind(@IdRes id: Int) = object : ReadOnlyProperty&lt;KotlinModel, V&gt; {
        override fun getValue(thisRef: KotlinModel, property: KProperty&lt;*&gt;): V {
            // This is not efficient because it looks up the view by id every time (it loses
            // the pattern of a &amp;quotholder&amp;quot to cache that look up). But it is simple to use and could
            // be optimized with a map
            @Suppress(&amp;quotUNCHECKED_CAST&amp;quot)
            return view?.findViewById(id) as V?
                ?: throw IllegalStateException(&amp;quotView ID $id for &#039;${property.name}&#039; not found.&amp;quot)
        }
    }
}علاوه بر اون میشه خیلی راحت و برحسب نیازمون اون کاستوم کنیم.حالا کافیه بیایم و مدل مون دوباره بسازیم :class HeaderViewWithKotlinModelEpoxy(
  private val title:String
) :KotlinModel(R.layout.header_view) {

    private val titleView by bind&lt;TextView&gt;(R.id.title)

    override fun bind() {
        titleView.text = title
    }
}همانطور که می بینید خیلی ساده model مون ساخته شد و دیگه نیازی به اون  annotationها و view holder ها نیست و خیلی راحت میشه دیتا رو از طریق constructor به Model فرستاد و از طریق Kotlin Model ویو که قرار inflate بشه رو بهش معرفی کرد.و در مرحله بعدی باید بریم سراغ controller دوم ) Epoxy Controller : برای اینکار اومدن از طریق Kotlin Extensions به سادگی و بدون نیاز به کلاس controller اونو پیاده سازی کردندheaderList.withModels {
    HeaderViewWithKotlinModelEpoxy(&amp;quotfood&amp;quot).apply{
        id(1) as KotlinModel
    }.addTo(this)
    HeaderViewWithKotlinModelEpoxy(&amp;quotgame&amp;quot).apply{
        id(2)
    }.addTo(this)
    HeaderViewWithKotlinModelEpoxy(&amp;quotcode&amp;quot).apply{
        id(3)
    }.addTo(this)
    HeaderViewWithKotlinModelEpoxy(&amp;quotbook&amp;quot).apply{
        id(4)
    }.addTo(this)
}که withModels یه extention که برای epoxy تعریف شده و از طریق اون و بدون نیاز به هیچ کلاس controller میشه همه مدل ها که شامل مدل های متفاوت هم می تونه باشه پیاده سازی کرد.نسب به کدهای قسمت قبل خیلی کمتر و کارمون خیلی ساده تر شد.سادگی در پیاده سازی و راحت بودنش صفحه رو شبیه یه پازل می کنه که کافی تیکه های پازل کنار هم گذاشت و راحت اون ساخت :))لایبرری epoxy کلی ویژگی های خوب دیگه ام داره که سعی می کنم توی مقاله های بعدی درباره اشون بنویسم.اگه تجربه ای از استفاده epoxy توی پروژه هاتون دارین خوشحال می شم زیر همین پست بنویسید.منابع : https://github.com/airbnb/epoxy/wiki </description>
                <category>Fatemeh Movassaghpour</category>
                <author>Fatemeh Movassaghpour</author>
                <pubDate>Thu, 17 Sep 2020 10:10:06 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش کار با Epoxy در اندروید - قسمت ۱</title>
                <link>https://virgool.io/MobileLab/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-epoxy-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D9%82%D8%B3%D9%85%D8%AA-%DB%B1-wc1tb9dgraus</link>
                <description>Epoxyتوی این مقاله قرار بگیم Epoxy چیه و چکارهایی می تونه برای ما انجام بده یا به عبارت دیگه چطور زندگی برامون راحت تر کنه :)تقریبا  برای همون پیش اومده که بخوایم لیست های پیچیده توی اندروید پیاده سازی کنیم خب راه حلی که براش بود اینه که بیایم برای recycler view مون تایپ های متفاوتی تعریف کنیم و لیست ها بر اون اساس پیاده سازی کنیم جدا از چالش هایی که اون حالت داره کلی boilerplate هم داریم حالا با epoxy میشه این کار ساده تر انجام داد در واقع شعارش هم همین پیاده سازی لیست های پیچیده به سادگی هست.این لایبری توسط شرکت Airbnb و برای پیاده سازی صفحات پیچیده با recycler view توسعه داده شده است.بریم که شروع کنیم :دو مفهوم در epoxy خیلی مهم هستند :اول ) Epoxy Model : آیتم های Recycler.ViewHolder کنترل می کند و در واقع کار اصلیش اینه که یک کلاس مدل را برای هر آیتم ایجاد می کند تا دیتا های مربوط به آن ها را نمایش بدهد. ضمنا یک کلاس immutable هست و کاری شبیه به view model انجام میدهد دیتا دریافتی برای نمایش به view میدهد.دوم ) Epoxy Controller : مشخص میکنه که کدام مدل ها باید به recyclerView برای نمایش اضافه شوند و از این طریق یک صفحه پیچیده کاملا ساده پیاده سازی کنیم.به سه روش زیر می توان Epoxy Model را ایجاد کرد : (در این مقاله از روش سوم استفاده می کنیم)۱ - custom view۲- data binding ۳- view holderاول epoxy به پروژه امون اضافه می کنیم :apply plugin: &#039;kotlin-kapt&#039; 

kapt {
    correctErrorTypes = true
}

dependencies {
      implementation  &#039;com.airbnb.android:epoxy:3.6.0&#039; 
     kapt &#039;com.airbnb.android:epoxy-processor:3.6.0&#039;
}بعد از اون آیتم های لیست رو می سازیم :&lt;?xml version=&amp;quot1.0&amp;quot encoding=&amp;quotutf-8&amp;quot?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&amp;quothttp://schemas.android.com/apk/res/android&amp;quot
    android:layout_width=&amp;quotwrap_content&amp;quot
    android:layout_height=&amp;quot56dp&amp;quot
    xmlns:app=&amp;quothttp://schemas.android.com/apk/res-auto&amp;quot&gt;

    &lt;TextView
        android:id=&amp;quot@+id/title&amp;quot
        android:layout_width=&amp;quotwrap_content&amp;quot
        android:layout_height=&amp;quotwrap_content&amp;quot
        android:text=&amp;quotHello World!&amp;quot
        app:layout_constraintBottom_toBottomOf=&amp;quotparent&amp;quot
        app:layout_constraintLeft_toLeftOf=&amp;quotparent&amp;quot
        app:layout_constraintRight_toRightOf=&amp;quotparent&amp;quot
        app:layout_constraintTop_toTopOf=&amp;quotparent&amp;quot /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;و بعد نوبت خود epoxy که به ui اکتیویتی اضافه بشه :&lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&amp;quothttp://schemas.android.com/apk/res/android&amp;quot
    xmlns:app=&amp;quothttp://schemas.android.com/apk/res-auto&amp;quot
    xmlns:tools=&amp;quothttp://schemas.android.com/tools&amp;quot
    android:layout_width=&amp;quotmatch_parent&amp;quot
    android:layout_height=&amp;quotmatch_parent&amp;quot
    tools:context=&amp;quot.MainActivity&amp;quot&gt;

   &lt;com.airbnb.epoxy.EpoxyRecyclerView
       android:id=&amp;quot@+id/headerList&amp;quot
       android:layout_width=&amp;quotmatch_parent&amp;quot
       android:layout_height=&amp;quotmatch_parent&amp;quot
       /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;
در مرحله بعد باید بریم و Epoxy Model را  درست کنیم که طبق چیزی که قبلا گفتیم ما از روش view holder استفاده می کنیم :@EpoxyModelClass(layout = R.layout.header_view)
abstract class HeaderViewWithViewHolderEpoxy : EpoxyModelWithHolder&lt;Holder&gt;(){

    @EpoxyAttribute lateinit var title : String

    override fun bind(holder: Holder) {
        holder.title.text = title
    }

}

class Holder:KotlinHolder() {
        val title by bind&lt;TextView&gt;(R.id.title)
}همون طور که می بینید توی خط اول و از طریق انوتیشن EpoxyModelClass لایه ای که باید infleted بشه رو بهش معرفی می کنیم. توی متد bind هم دیتا دریافتی از طریق EpoxyAttribute ها به ویو bind میکنه.اگه از java استفاده می کنید که view holder شبیه به همون view holder ریسایکلر ویو هست فقط از EpoxyHolder ارث بری می کند.  اما برای kotlin میشه کلاس KotlinHolder به پروژه اضافه کرد و خیلی راحت از اون استفاده کنیم.حالا که epoxy model ما ساخته شد به یک epoxy controller احتیاج داریم که برای نمایش باید به اون اضافه شود.class HeaderViewController : EpoxyController() {
    
    override fun buildModels() {
      HeaderViewWithKotlinModelEpoxy(&amp;quotfood&amp;quot) 
      .id(1)// به هر آیتم باید یک ایدی نسبت داده شود
     .addTo(this) / /  به این طریق مدل به کنترلر اضافه می کنیم
      HeaderViewWithKotlinModelEpoxy(&amp;quotgame&amp;quot).id(2).addTo(this)
      HeaderViewWithKotlinModelEpoxy(&amp;quotcode&amp;quot).id(3).addTo(this)
    }
}هر کنترلر یک متد buildModels داره که از طریق اون مشخص میشه که چه آیتم هایی باید نمایش داده شوند. نکته خوب epoxy  درواقع همین جاست که توی این متد cotroller هر model که قبلا ساخته باشیم می شه گذاشت و کاملا داینامیک هست.(در این مثال فقط از یک model استفاده شده اما از هر چندmodel که بخواهیم میتونم استفاده کنیم.)یه حالت هم داره برای تعریف دو تایپ که در این لینک می تونید بیشتر بخونید. دیگه فقط قسمت اخرش مونده که اینو به ریسایکلر مون معرفی کنیم تا لیست مورد نظر ما رو نمایش بدهval controller = HeaderViewController()
controller.isDebugLoggingEnabled = true // برای دیباگ کردن و چک کردن لیست بسیار کاربردی هست اما ضروری نیست.

headerList.apply {
    layoutManager = LinearLayoutManager(this@MainActivity,LinearLayoutManager.VERTICAL,false)
    adapter = controller.adapter
    controller.requestModelBuild() // برای زمانی که دیتا تغییر می کنه استفاده میشود.
}
هر کنترلر یک adaper داره که برای ست کردن adapter ریسایکلر ویو می تونیم از اون استفاده کنیم.متد requestModelBuild زمانی که دیتا تغییر کنه دوباره buildModel فراخوانی میکنه تا تغییرات جدید به مدل ها بایند شده و آپدیت شوند.حالا ما از epoxy برای پروژه امون استفاده کردیم.چیزی که epoxy برای من جذاب تر کرد قسمت کاتلینش بود که توی مقاله بعدی با یه کلاس ساده تر و خیلی راحت modelهامون می سازیم و استفاده می کنیم.داکیومنت خود epoxy که لینکش توی قسمت منابع اومده خیلی کامل تر توضیح داده و پیشنهاد میکنم حتما مطالعه کنید.قسمت دوممنابع : https://github.com/airbnb/epoxy/wiki  https://android.jlelse.eu/simplifying-recycler-view-with-epoxy-in-kotlin-nachos-tutorial-series-946d22116d57 </description>
                <category>Fatemeh Movassaghpour</category>
                <author>Fatemeh Movassaghpour</author>
                <pubDate>Mon, 14 Sep 2020 18:43:41 +0430</pubDate>
            </item>
                    <item>
                <title>چطور gradle با کاتلین بنویسیم</title>
                <link>https://virgool.io/@fatemeh_msp/%DA%86%D8%B7%D9%88%D8%B1-gradle-%D8%A8%D8%A7-%DA%A9%D8%A7%D8%AA%D9%84%DB%8C%D9%86-%D8%A8%D9%86%D9%88%DB%8C%D8%B3%DB%8C%D9%85-igr2lbiwurfo</link>
                <description>بعد از مدت ها که تصمیم گرفته بودم امروز بلاخره اولین پست ویرگول می نویسم (امیدوارم ادامه داشته باشه) خب بریم سر اصل مطلب قرار تو این پست گریدل با کاتلین بنویسیم شاید یکم باهاش آشتی کنیم :)سایت gradle در تعریف پیاده سازی با کاتلین آورده :Gradle + Kotlin =  ⚡️ ? Kotlin + Gradle: a technology combination sure to foster developer happiness and productivity. حالا اگه بازم سوال پیش میاد که چرا باید از کاتلین استفاده کنیم ؟1- چون کد کاتلین هست و خیلی راحت با Ctrl + B میشه بین کدها سویچ کرد.2- خیلی راحت میشه کدها را refactor کرد.3- و error highlighting سریعی دارد.در چند قدم ساده یه گریدل با کاتلین می نویسیم اگه می خوایین کدهای تمیزتری داشته باشید قدم اول و دوم انجام بدین در غیر این صورت اجباری نیستند و می تونید مستقیم قدم سوم انجام بدین.قدم اول ) ایجاد دایرکتوری buildSrc :buildSrcاین دایرکتوری همون ویژگی های گریدل داره و ابزارهایی داره که در همه فایل های build ها میشه از اون استفاده کرد.اگه میخوایین بیشتر در جریان باشید این لینک مطالعه کنید.قدم دوم ) ایجاد دو فایل درون buildSrc :1- build.gradle.kts2- Dependencies .kt (Inside src/main/kotlin package) یه نکته اینکه به پسوند فایل های ایجاد شده دقت کنید. برای فایل های گریدل از kts. و Dependensies که یک فایل ساده کاتلین هست kt. استفاده می شود.bulid.gradle.kts https://gist.github.com/FatemehMsp/f248752cdf3367234b1a375e6f1bbc5a dependencies .kt https://gist.github.com/FatemehMsp/c23d610be4f4c8416faa12727ddc711b در واقع فایل بالا از اون کدهاس که یکبار مینویسم و درباقی پروژه میشه استفاده اش کنیم و من فقط موارد اولیه که یک پروژه اندروید استدیو خودش می سازه رو نوشتم و شما می تونید همه dependencies هایی که پروژه اتون احتیاج داره بنوسید و خیلی راحت باهاش کارکنید چون یک فایل ساده کاتلین هست.قدم سوم ) بازنویسی فایل های گریدل پروژه :در ادامه باید هر دو فایل گریدل از اول بازنویسی کنیم تغییراتش کم هست مثلا یک سری = و () به فایل ها اضافه می شوند ولی در عوض فایل های زیباتری داریم :)نکته مهم این مرحله اینه که هر دوفایل گریدل پروژه باید rename شوند به build.gradle.kts. حالت های مختلف نوشتن کدهای plugin و  dependencies در ادامه می بینید ...build.gradle.kts (project) https://gist.github.com/FatemehMsp/18df1a70f5898a4c09dd374e5c210fef build.gradle.kts (module:app) https://gist.github.com/FatemehMsp/a354ae9d9f97315ea92593c6fbb09c26 اگه هنوز به تغییر علاقه داشتید :) فایل settings.gradle  به صورت زیر میتونید بازنویسی کنید include (&quot;:app&quot;)خب بهتون تبریک میگم فایل گریدل تون به این سادگی تبدیل کردید و حالا خیلی راحت میشه فهمیدشون :)و اگه دوست دارید بیشتر درباره این موضوع مطالعه کنید لینک های منابع انتهای مقاله براتون گذاشتم.منابع :https://proandroiddev.com/the-new-way-of-writing-build-gradle-with-kotlin-dsl-script-8523710c9670https://proandroiddev.com/migrate-to-gradle-kotlin-dsl-in-4-steps-f3e3b27e1f4dhttps://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sourceshttps://gradle.org/kotlin/</description>
                <category>Fatemeh Movassaghpour</category>
                <author>Fatemeh Movassaghpour</author>
                <pubDate>Wed, 11 Mar 2020 21:48:31 +0330</pubDate>
            </item>
            </channel>
</rss>