Coverage Summary for Class: BaseDialogFragment (kr.open.library.simple_ui.xml.ui.components.dialog.normal)

Class Class, % Method, % Branch, % Line, % Instruction, %
BaseDialogFragment 100% (1/1) 100% (6/6) 100% (2/2) 100% (15/15) 100% (53/53)


 package kr.open.library.simple_ui.xml.ui.components.dialog.normal
 
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.annotation.CallSuper
 import androidx.annotation.LayoutRes
 import kr.open.library.simple_ui.xml.ui.components.dialog.root.RootDialogFragment
 
 /**
  * A basic DialogFragment that handles layout inflation automatically without ViewBinding or DataBinding.<br>
  * Extends RootDialogFragment to inherit dialog functionality and permission management.<br><br>
  * ViewBinding이나 DataBinding 없이 레이아웃 인플레이션을 자동으로 처리하는 기본 DialogFragment입니다.<br>
  * RootDialogFragment를 확장하여 다이얼로그 기능과 권한 관리를 상속받습니다.<br>
  *
  * **Why this class exists / 이 클래스가 필요한 이유:**<br>
  * - Android DialogFragments require manual layout inflation and view lifecycle management for every dialog.<br>
  * - This class eliminates boilerplate by accepting a layout resource ID and automatically handling inflation and cleanup.<br>
  * - Provides safe rootView access with null safety checks to prevent crashes after onDestroyView().<br>
  * - Ideal for simple dialogs that don't need ViewBinding/DataBinding overhead.<br><br>
  * - Android DialogFragment는 매번 수동으로 레이아웃 인플레이션과 뷰 생명주기 관리가 필요합니다.<br>
  * - 이 클래스는 레이아웃 리소스 ID를 받아 자동으로 인플레이션과 정리를 처리하여 보일러플레이트를 제거합니다.<br>
  * - onDestroyView() 이후 크래시를 방지하기 위해 null 안전성 검사가 포함된 안전한 rootView 접근을 제공합니다.<br>
  * - ViewBinding/DataBinding 오버헤드가 필요하지 않은 간단한 다이얼로그에 이상적입니다.<br>
  *
  * **Design decisions / 설계 결정 이유:**<br>
  * - Uses constructor parameter for layout resource ID to enable simple single-line class declaration.<br>
  * - Uses nullable _rootView with public rootView accessor that throws exception after onDestroyView() for safe access.<br>
  * - Extends RootDialogFragment to inherit dialog functionality (animation, gravity, permissions).<br>
  * - Automatically sets rootView to null in onDestroyView() to prevent memory leaks.<br><br>
  * - 간단한 한 줄 클래스 선언을 위해 생성자 파라미터로 레이아웃 리소스 ID를 사용합니다.<br>
  * - onDestroyView() 이후 안전한 접근을 위해 nullable _rootView와 예외를 던지는 public rootView 접근자를 사용합니다.<br>
  * - RootDialogFragment를 상속하여 다이얼로그 기능(애니메이션, gravity, 권한)을 상속받습니다.<br>
  * - 메모리 누수를 방지하기 위해 onDestroyView()에서 자동으로 rootView를 null로 설정합니다.<br>
  *
  * **Important notes / 주의사항:**<br>
  * - Access rootView property only between onViewCreated() and onDestroyView() - accessing after onDestroyView() throws IllegalStateException.<br>
  * - Use findViewById() on rootView to access child views instead of ViewBinding.<br>
  * - For dialogs needing ViewBinding or DataBinding, use BaseViewBindingDialogFragment or BaseDataBindingDialogFragment instead.<br><br>
  * - rootView 프로퍼티는 onViewCreated()와 onDestroyView() 사이에서만 접근 - onDestroyView() 이후 접근 시 IllegalStateException 발생.<br>
  * - ViewBinding 대신 rootView에서 findViewById()를 사용하여 자식 뷰에 접근하세요.<br>
  * - ViewBinding이나 DataBinding이 필요한 다이얼로그는 BaseViewBindingDialogFragment 또는 BaseDataBindingDialogFragment를 사용하세요.<br>
  *
  * **Usage / 사용법:**<br>
  * 1. Extend this class with your DialogFragment and pass the layout resource ID.<br>
  * 2. Access views through findViewById() on rootView in onViewCreated() or later lifecycle methods.<br>
  * 3. No need to manually handle view inflation or cleanup - it's done automatically.<br><br>
  * 1. DialogFragment에서 이 클래스를 상속받고 레이아웃 리소스 ID를 전달하세요.<br>
  * 2. onViewCreated() 또는 이후 생명주기 메서드에서 rootView의 findViewById()를 통해 뷰에 접근하세요.<br>
  * 3. 뷰 인플레이션이나 정리를 수동으로 처리할 필요 없음 - 자동으로 수행됩니다.<br>
  *
  * **Usage example:**<br>
  * ```kotlin
  * class ConfirmDialog : BaseDialogFragment(R.layout.dialog_confirm) {
  *     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  *         super.onViewCreated(view, savedInstanceState)
  *         rootView.findViewById<TextView>(R.id.tvTitle).text = "Confirm"
  *         rootView.findViewById<Button>(R.id.btnOk).setOnClickListener {
  *             safeDismiss()
  *         }
  *     }
  * }
  * ```
  *
  * @param layoutRes The layout resource ID for the dialog.<br><br>
  *                  다이얼로그의 레이아웃 리소스 ID.<br>
  *
  * @param isAttachToParent Whether to attach the inflated view to the parent container.<br><br>
  *                         인플레이션된 뷰를 부모 컨테이너에 첨부할지 여부.<br>
  *                         DialogFragment에서는 특별한 경우가 아니라면 기본값 `false` 사용을 권장합니다.<br>
  *                         반환된 root view는 DialogFragment framework가 다시 처리하므로 `true` 사용 시 parent 중복 attach 예외가 발생할 수 있습니다.<br>
  *
  * @see RootDialogFragment For base class with dialog and permission features.<br><br>
  *      다이얼로그 및 권한 기능이 있는 기본 클래스는 RootDialogFragment를 참조하세요.<br>
  *
  * @see ParentBindingViewDialogFragment For the abstract parent class of all binding-enabled dialog fragments.<br><br>
  *      모든 바인딩 지원 DialogFragment의 추상 부모 클래스는 ParentBindingViewDialogFragment를 참조하세요.<br>
  *
  * @see BaseViewBindingDialogFragment For ViewBinding-enabled DialogFragment.<br><br>
  *      ViewBinding을 사용하는 DialogFragment는 BaseViewBindingDialogFragment를 참조하세요.<br>
  *
  * @see BaseDataBindingDialogFragment For DataBinding-enabled DialogFragment.<br><br>
  *      DataBinding을 사용하는 DialogFragment는 BaseDataBindingDialogFragment를 참조하세요.<br>
  */
 public abstract class BaseDialogFragment : RootDialogFragment {
     @LayoutRes
     private val layoutRes: Int
     private val isAttachToParent: Boolean
 
     constructor(layoutRes: Int) : this(layoutRes, false)
 
     constructor(layoutRes: Int, isAttachToParent: Boolean) : super() {
         this.layoutRes = layoutRes
         this.isAttachToParent = isAttachToParent
     }
 
     /**
      * Internal backing field for rootView.<br><br>
      * rootView의 내부 백킹 필드입니다.<br>
      */
     private var rootView: View? = null
 
     /**
      * The root view of the dialog's layout.<br>
      * Throws IllegalStateException if accessed after onDestroyView().<br><br>
      * 다이얼로그 레이아웃의 루트 뷰입니다.<br>
      * onDestroyView() 이후에 접근하면 IllegalStateException이 발생합니다.<br>
      *
      * **Usage / 사용법:**<br>
      * Access views using findViewById() in lifecycle methods between onViewCreated() and onDestroyView().<br><br>
      * onViewCreated()와 onDestroyView() 사이의 생명주기 메서드에서 findViewById()를 사용하여 뷰에 접근합니다.<br>
      *
      * **Example / 예시:**<br>
      * ```kotlin
      * override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      *     super.onViewCreated(view, savedInstanceState)
      *     rootView.findViewById<TextView>(R.id.tvTitle).text = "Hello"
      * }
      * ```
      *
      * @return The root view of the dialog.<br><br>
      *         다이얼로그의 루트 뷰.<br>
      * @throws IllegalStateException if accessed after onDestroyView().<br><br>
      *                               onDestroyView() 이후에 접근하는 경우.<br>
      */
     protected fun getRootView(): View {
         if (rootView == null) {
             throw IllegalStateException("rootView is not initialized.")
         }
         return rootView!!
     }
 
     @CallSuper
     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
         rootView = inflater.inflate(layoutRes, container, isAttachToParent)
         return getRootView()
     }
 
     @CallSuper
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         getRootView().let { rootView ->
             config.updateBackgroundColor(rootView)
         }
     }
 
     @CallSuper
     override fun onDestroyView() {
         super.onDestroyView()
         rootView = null
     }
 }