Skip to content

utility for developing Android applications with view binding, extension functions, custom view and code shortening

License

Notifications You must be signed in to change notification settings

imanfz/android-utils

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Android Utils

Maven Central

Preview

enter image description here

Feature

How to use

Maven central

  dependencies {
      implementation 'io.github.imanfz:android-utils:{latest version}'
  }

Base

class MainActivity : BaseActivity<ActivityMainBinding>() {
    ...
}

or if you have custom BaseActivity, you can extends it:

class BaseActivity<B : ViewBinding> : BaseActivity<B>() {
    ...
}
class SampleSheet : BaseBottomSheetDialog<FragmentSampleSheetBinding>() {
    ...
}
class SampleFragment : BaseFragment<FragmentSampleBinding>() {
    ...
}

or if you have custom BaseFragment, you can extends it:

class BaseFragment<B : ViewBinding> : BaseFragment<B>() {
    ...
}

Common

for handle bug live data in fragment after on backstack

  val dataState = SingleLiveData<String>()

Dialog

  val image = url or uri.toString()
  ImageViewerDialog.newInstance(image).show(supportFragmentManager, tag)
class MainActivity : BaseActivity<ActivityMainBinding>() {
    ...
    binding.apply {
        btnLoading.setSafeOnClickListener {
            showLoading()
            lifecycle.coroutineScope.apply {
               launch {
                  delay(3000)
                  hideLoading()
               }
            }
        }
    }
}

Extension

class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate()
        ...
        
        // keyboard
        hidekeyboard()
        showKeyboard()
        
        // SnackBar
        longSnack("Hello World")
        shortSnack("Hello World")
    }
}
class MainActivity : BaseActivity<ActivityMainBinding>() {

    private val listPermission = listOf(
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    )
    
    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate()
        ...
       
        // Toast
        longToast("Hello World")
        shortToast("Hello World")
        
        if (hasPermission(Manifest.permission.CAMERA)) {
            logi("GRANTED")
        }
        
        if(hasPermission(listPermission.toTypedArray())) {
            logi("GRANTED")
        } else {
            requestPermission()
        }
        
        startActivity<HomeActivity>()
        // or
        startActivity<HomeActivity>(Bundle().apply{
            putString("A", "tes")
        })
        
        startActivity<HomeActivity>()
        // or
        startActivityAndClearTask<HomeActivity>(Bundle().apply{
            putString("A", "tes")
        })
        
        startActivityClearTop<HomeActivity>()
        // or
        startActivityClearTop<HomeActivity>(Bundle().apply{
            putString("A", "tes")
        })
        
        showBasicDialog(
            "Title",
            "Message",
            okClicked = { // nullable
                logi("OK")
            },
            cancelClicked = { // nullable
                logi("Cancel")
            }
        )
    }
}

update language

open class BaseActivity : AppCompatActivity() {
    override fun attachBaseContext(newBase: Context) {
        newBase.apply {
            val prefs = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
            var lang = prefs.getString(AppPreference.KEY_LANGUAGE, "en") ?: "en"
            super.attachBaseContext(updateBaseContextLocale(lang))
        }
    }
}
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate()
    ...
        val number = binding.etNumber.getString()
    }
}
class HomeFragment : BaseFragment<FragmentHomeBinding>() {

    private val listPermission = listOf(
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    )
    
    override fun onViewCreated(savedInstanceState: Bundle) {
        super.onViewCreated()
        ...
       
        // SnackBar
        longSnack("Hello World")
        shortSnack("Hello World")
        
        // Toast
        longToast("Hello World")
        shortToast("Hello World")
        
        // for finished parent activity
        finish()
        
        copyTextToClipboard(binding.etNumber.getString(), "Text Copied")
        
        if (hasPermission(Manifest.permission.CAMERA)) {
            logi("GRANTED")
        }
        
        if(hasPermission(listPermission.toTypedArray())) {
            logi("GRANTED")
        } else {
            requestPermission()
        }
        
        startActivity<HomeActivity>()
        // or
        startActivity<HomeActivity>(Bundle().apply{
            putString("A", "tes")
        })
        
        startActivity<HomeActivity>()
        // or
        startActivityAndClearTask<HomeActivity>(Bundle().apply{
            putString("A", "tes")
        })
        
        startActivityClearTop<HomeActivity>()
        // or
        startActivityClearTop<HomeActivity>(Bundle().apply{
            putString("A", "tes")
        })
        
        showDialog(
            "Title",
            "Message",
            okClicked = { // nullable
                logi("OK")
            },
            cancelClicked = { // nullable
                logi("Cancel")
            }
        )
    }
}
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate()
    ...
        val needDp = 8.toDp()
        val needPx = 8.toPx()
    }
}
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate()
    ...
        // basic
        binding.ivAvatar.loadImage("url")
        // or
        val uri = ...
        binding.ivAvatar.loadImage(uri)
        // or
        binding.ivAvatar.loadImage(R.drawable.ic_avatar)
        
        // circle
        binding.ivAvatar.loadCircleImage("url")
        // or
        val uri = ...
        binding.ivAvatar.loadCircleImage(uri)
        // or
        binding.ivAvatar.loadCircleImage(R.drawable.ic_avatar)
        
        // rounded (default radius = 10, can modify)
        binding.ivAvatar.loadRoundedImage("url", 20)
        // or
        val uri = ...
        binding.ivAvatar.loadRoundedImage(uri, 15)
        // or
        binding.ivAvatar.loadRoundedImage(R.drawable.ic_avatar, 25)
        
        // ShapeableImageView
        binding.shapableIv.setRadius(10)
    }
}
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate()
    ...
    
        // TAG auto generate with class T.TAG
        // example use get HomeFragment TAG
        HomeFragment().TAG
        
        logv("Hello World")
        logi("Hello World")
        logw("Hello World")
        logd("Hello World")
        loge("Hello World")
    }
}
findNavController().safeNavigate(action)
findNavController().safeNavigate(R.id.navigateto)
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate()
    ...
    
        binding.rvMain.apply {
            setup() // default is LinearLayourManager
            // or
            setup(GridLayoutManager(this, 4))
            
            addVerticalItemDecoration() // default
            // or
            addVerticalItemDecoration(ContexCompact.getDrawable(this, R.drawable.rect_blue)) // with drawable nullable
            
            addDividerVerticalItemExLast(ContexCompact.getDrawable(this, R.drawable.rect_blue)) // with drawable nullable
            
            addDividerVerticalItemExHeader(ContexCompact.getDrawable(this, R.drawable.rect_blue)) // with drawable nullable
            
            addHorizontalItemDecoration()
            
            addHorizontalSpaceItem(space = 8)
            
            addGridSpaceItem(
                spaceCount: 4,
                rowSpace: 8f,
                columnSpacing: 24f
            )              
        }
    }
}
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate()
    ...
    
        "11/11/2022".toDate("dd/MM/yyyy")
        "Iman Faizal".apply {
            logi(getFirstName()) // output: Iman
            logi(getLastName()) // output: Faizal
            // get initial can set limitation for your need initial name, example getInitial(limit = 1) -> result I
            logi(getInitials()) // output: IF
            logi(getStartAndEndOfSubstring("Fai")) // output (5, 7) 
        }
        "afas37h38f".getNumeber() // output: 3738
         
    }
}
fromHtmlText(text: String)
setColorOfSubstring(substring: String, color: Int)
startDrawable(drawableRes: Int)
startDrawable(drawable: Drawable?) 
endDrawable(drawableRes: Int)
endDrawable(drawable: Drawable?) 
AutoCompleteTextView.setupDropdownUI()
  • ViewHolder
    inner class CharactersViewHolder(binding: RowCharacterBinding): BindingViewHolder<RowCharacterBinding>(binding) {    
        fun bind(item: Character) {
            ....
            binding.tvName.text = item.name
            ....
            binding.root.setOnClickListener {
               ....
            }
        }    
    }
    
  • Adapter
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return CharactersViewHolder(parent.toBinding())
    }
    
  • BaseActivity
  • BaseFragment
  • BaseBottomSheetDialog
  • BaseDialogFragment
class MainActivity : BaseActivity<ActivityMainBinding>() {
    override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate()
    ...
        binding.apply {
            imageView.gone() // hide
            imageView.isGone() // true or false
            imageView.visible() // visibile
            imageView.isVisible() // true or false
            imageView.invisible() // invisibile
            imageView.isInvisible() // true or false
            imageView.enabled()
            imageView.disabled()
            
            root.snackBarWithAction(
                "Message",
                "Action Label",
                onClicked = {
                    logi("OK click")
                }
            )
        }
    }
}
class MainActivity : BaseActivity<ActivityMainBinding>() {
    private lateinit var appUpdateUtils: AppUpdateUtils
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        appUpdateUtils = AppUpdateUtils(this)
    }
    
    @Deprecated("Deprecated in Java")
    @Suppress("DEPRECATION")
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        appUpdateUtils.onActivityResult(requestCode, resultCode)
        super.onActivityResult(requestCode, resultCode, data)
    }
}

Custom UI

in layout

     <com.imanfz.utility.ui.ReadMoreTextView
        android:id="@+id/readMoreTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:readMoreText="Show" // default Read More
        app:readMoreTextColor="@color/colorPrimary" // default readmore_color
        app:readMoreMaxLine="2" // default 4
        android:text="testsfsf sfks\nsfsfsf\nsfjfsjsfj\njsfjs oke bos"

in layout

 <com.imanfz.utility.ui.LoadingButton
        android:id="@+id/loading_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Loading Button"
        android:textColor="#ffffff"
        app:lb_buttonColor="@color/bluePrimaryDark"
        app:lb_loaderColor="@color/redPrimary"
        app:lb_loaderWidth="2dp"
        app:lb_loaderMargin="8dp"
        app:lb_isLoading="false"
        app:lb_cornerRadius="8dp"
        app:lb_isCircular="false"
        app:lb_isShadowEnable="false"
        app:lb_shadowColor="@color/yellowPrimary"
        app:lb_shadowHeight="2dp"
        app:lb_isStrokeEnable="true"
        app:lb_strokeWidth="2dp"
        app:lb_strokeColor="@color/redPrimary" />

in activity/fragment

loadingButton.apply {
    setSafeOnClickListener {
        showLoading()
        delayOnLifecycle {
            hideLoading()
        }
    }
}

Utility

getCurrentDateTime() // date
getCurrentDateTimeMils() // long
showDatePicker(context: Context) { date -> // string return
  ...
}
getUUID() // UUID
getDeviceModel()
getDeviceName()
getDeviceAPILevel()
getDeviceOSCode()
getDeviceOSName()
getDeviceTimeZone()
getDeviceLanguage()
setLightTheme()
setDarkTheme()

mandatory, your model class extend the BaseModel. The detail base model is:

interface BaseModel {
    fun contains(someValue: String): Boolean = false
    fun isItemSameWith(value: BaseModel): Boolean = false
    fun isContentSameWith(value: BaseModel): Boolean = false
}

and how to use it

@Parcelize
data class Example(
  ...
  ...
): Parcelable, BaseModel
ItemDiffCallback<Example>()
convertDpToPixel(dp: Float, context: Context?): Float
convertPixelsToDp(px: Float, context: Context?): Float
isConnectionOn(context: Context): Boolean
isInternetAvailable(): Boolean

NetworkStatusUtils(context).observe(this, {
    when(it) {
        NetworkStatus.Available -> shortToast("Network Connection Established")
        NetworkStatus.Unavailable -> shortToast("No Internet")
        NetworkStatus.Lost -> shortToast("Reconnecting")
    }
})
isDeviceRooted(): Boolean
reverse(duration: Long = 2000L): Shimmer
thinStraightTransparent(): Shimmer
sweep(
    direction: Int = Shimmer.Direction.TOP_TO_BOTTOM,
    tilt: Float = 0f
): Shimmer
spotlight(
    alpha: Float = 0f,
    duration: Long = 2000L,
    dropOff: Float = 0.1f,
    intensity: Float = 0.35f,
    shape: Int = Shimmer.Shape.RADIAL
): Shimmer

// extension
show()
hide()
isValidInput(text: String, textInputLayout: TextInputLayout): Boolean
isValidInputLength(text: String, textInputLayout: TextInputLayout): Boolean
isValidEmail(emailText: String, textInputLayout: TextInputLayout): Boolean
isValidPhone(phone: String, textInputLayout: TextInputLayout): Boolean
isValidPhoneOrEmail(text: String, textInputLayout: TextInputLayout): Boolean
isValidPassword(password: String, textInputLayout: TextInputLayout): Boolean
isValidStrongPassword(password: String, textInputLayout: TextInputLayout): Boolean

enum class PasswordValidation {
    LOWERCASE, UPPERCASE, DIGIT, CHARACTER
}
isNewValidPassword(password: String): List<PasswordValidation>
isMatchPassword(password: String, confirmPassword: String, textInputLayout: TextInputLayout): Boolean
DepthPageTransformer()
ZoomOutPageTransformer()

Other

putIsLogin(value: Boolean)
isLogin(): Boolean
putFirstTimeLaunch(value: Boolean)
isFirstTimeLaunch(): Boolean
isFirstLogin(): Boolean
putIsFirstLogin(value: Boolean)
putString(key: String, text: String)
getString(key: String): String
putInt(key: String, value: Int)
getInt(key: String): Int
clear()
// model
put(UserModel(), USER_KEY)
get<UserModel>(USER_KEY) // nullable

// list model
putList(listUserModel, LIST_KEY)
geListt<UserModel>(LIST_KEY)

putInitialNameAvatar(bitmap: Bitmap)
getInitialNameAvatar(): Bitmap?