diff --git a/Demo/app/build.gradle b/Demo/app/build.gradle index 389b864..4961430 100644 --- a/Demo/app/build.gradle +++ b/Demo/app/build.gradle @@ -1,6 +1,7 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' + id 'kotlin-kapt' } android { @@ -32,13 +33,25 @@ android { kotlinOptions { jvmTarget = '17' } + + buildFeatures { + viewBinding true + dataBinding true + } } dependencies { - + def lifecycle_version = "2.6.1" implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" + implementation 'androidx.fragment:fragment-ktx:1.5.7' + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + implementation "androidx.core:core-splashscreen:1.0.1" + implementation "androidx.preference:preference-ktx:1.2.0" + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/Demo/app/src/main/AndroidManifest.xml b/Demo/app/src/main/AndroidManifest.xml index 3495777..9ee8eb5 100644 --- a/Demo/app/src/main/AndroidManifest.xml +++ b/Demo/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> + android:theme="@style/Theme.App.Starting" + tools:targetApi="31"> + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/DemoApplication.kt b/Demo/app/src/main/java/com/krunal/demo/DemoApplication.kt new file mode 100644 index 0000000..45e7964 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/DemoApplication.kt @@ -0,0 +1,22 @@ +package com.krunal.demo + +import android.app.Application +import com.krunal.demo.uicomponents.helpers.PreferenceHelper + +class DemoApplication: Application() { + + override fun onCreate() { + super.onCreate() + + instance = this + + /** + * Initialize [PreferenceHelper] + */ + PreferenceHelper.initialize(applicationContext) + } + + companion object { + lateinit var instance: Application + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/UIComponentsActivity.kt b/Demo/app/src/main/java/com/krunal/demo/UIComponentsActivity.kt new file mode 100644 index 0000000..d03fa42 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/UIComponentsActivity.kt @@ -0,0 +1,31 @@ +package com.krunal.demo + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import com.krunal.demo.uicomponents.ButtonFragment +import com.krunal.demo.uicomponents.CoordinatorLayoutFragment +import com.krunal.demo.uicomponents.ThemeFragment +import com.krunal.demo.uicomponents.cardscreen.CardFragment +import com.krunal.demo.uicomponents.helpers.ThemeHelper + +class UIComponentsActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + installSplashScreen() + setupTheme() + setContentView(R.layout.activity_uicomponents) + setupFragment() + } + + private fun setupTheme() { + setTheme(ThemeHelper.getThemeResource(ThemeHelper.getThemeAccent())) + } + + private fun setupFragment() { + supportFragmentManager.beginTransaction() + .replace(R.id.uiComponentsFragment, CoordinatorLayoutFragment()) + .commit() + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/AppBarFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/AppBarFragment.kt new file mode 100644 index 0000000..c7fe0e0 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/AppBarFragment.kt @@ -0,0 +1,36 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.SearchView +import androidx.fragment.app.Fragment +import com.google.android.material.color.MaterialColors +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentAppBarBinding +import com.krunal.demo.uicomponents.extentions.getThemeColor + +class AppBarFragment : Fragment(R.layout.fragment_app_bar) { + + private lateinit var binding: FragmentAppBarBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentAppBarBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupAppBars() + } + + private fun setupAppBars() { + binding.tbItems.inflateMenu(R.menu.toolbar_menu) + val searchItem = binding.tbSearch.menu.findItem(R.id.miSearch) + val searchView = searchItem.actionView as SearchView + searchView.isIconified = false + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/ButtonFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ButtonFragment.kt new file mode 100644 index 0000000..9d3dd7f --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ButtonFragment.kt @@ -0,0 +1,57 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.View.OnClickListener +import android.view.ViewGroup +import android.widget.Toast +import androidx.core.view.children +import androidx.fragment.app.Fragment +import com.google.android.material.button.MaterialButton +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentButtonBinding + +class ButtonFragment : Fragment(R.layout.fragment_button), OnClickListener { + + private lateinit var binding: FragmentButtonBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentButtonBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupClickListener() + } + + override fun onClick(view: View?) { + (view as? MaterialButton)?.let { + Toast.makeText(requireContext(), "${it.text} clicked", Toast.LENGTH_SHORT).show() + } + } + + private fun setupClickListener() { + + binding.btnNormal.setOnClickListener(this) + binding.btnBordered.setOnClickListener(this) + binding.appCompatButton.setOnClickListener(this) + binding.btnDisabled.setOnClickListener(this) + binding.btnOutlined.setOnClickListener(this) + binding.btnText.setOnClickListener(this) + binding.imgBtnImage.setOnClickListener(this) + binding.btnInfo.setOnClickListener(this) + binding.btnGradient.setOnClickListener(this) + + binding.switchEnable.setOnCheckedChangeListener { btn, checked -> + binding.root.children + .filterNot { it == binding.switchEnable } + .forEach { it.isEnabled = checked } + btn.text = + if (checked) getString(R.string.enabled_switch) else getString(R.string.disabled_switch) + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/CheckboxFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/CheckboxFragment.kt new file mode 100644 index 0000000..329c6dd --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/CheckboxFragment.kt @@ -0,0 +1,58 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.CompoundButton +import android.widget.CompoundButton.OnCheckedChangeListener +import android.widget.Toast +import androidx.fragment.app.Fragment +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentCheckboxBinding + +class CheckboxFragment : Fragment(R.layout.fragment_checkbox), OnCheckedChangeListener { + + private lateinit var binding: FragmentCheckboxBinding + private var selectedLanguages = mutableListOf() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentCheckboxBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupListeners() + } + + private fun setupListeners() { + selectedLanguages.add("English") + selectedLanguages.add("Hindi") + binding.cbEnglish.setOnCheckedChangeListener(this) + binding.cbHindi.setOnCheckedChangeListener(this) + binding.cbGujarati.setOnCheckedChangeListener(this) + binding.cbSpanish.setOnCheckedChangeListener(this) + binding.btnSaveChanges.setOnClickListener { + Toast.makeText(requireContext(), selectedLanguages.joinToString(), Toast.LENGTH_SHORT) + .show() + } + } + + override fun onCheckedChanged(btn: CompoundButton?, isChecked: Boolean) { + val language = when (btn) { + binding.cbEnglish -> "English" + binding.cbHindi -> "Hindi" + binding.cbGujarati -> "Gujarati" + binding.cbSpanish -> "Spanish" + else -> "" + } + if (isChecked) { + selectedLanguages.add(language) + } else { + selectedLanguages.remove(language) + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/ChipFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ChipFragment.kt new file mode 100644 index 0000000..e1986a4 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ChipFragment.kt @@ -0,0 +1,55 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.widget.addTextChangedListener +import androidx.fragment.app.Fragment +import com.google.android.material.chip.Chip +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentChipBinding + +class ChipFragment : Fragment(R.layout.fragment_chip) { + + private lateinit var binding: FragmentChipBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentChipBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupChips() + } + + private fun setupChips() { + binding.etChip.addTextChangedListener { + binding.tilChip.isEndIconVisible = binding.etChip.text.isNullOrEmpty().not() + } + + binding.etChip.setOnEditorActionListener { _, _, _ -> + addChip() + true + } + + binding.tilChip.setEndIconOnClickListener { + addChip() + } + } + + private fun addChip() { + val chip = Chip(requireContext()) + chip.text = binding.etChip.text + chip.setOnCloseIconClickListener { binding.cgProgrammatically.removeView(it) } + chip.setCloseIconResource(R.drawable.ic_cross) + chip.isCloseIconVisible = true + binding.cgProgrammatically.addView(chip) + binding.etChip.text?.clear() + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/CoordinatorLayoutFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/CoordinatorLayoutFragment.kt new file mode 100644 index 0000000..246e9ba --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/CoordinatorLayoutFragment.kt @@ -0,0 +1,45 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.fragment.app.Fragment +import com.google.android.material.behavior.SwipeDismissBehavior +import com.google.android.material.snackbar.BaseTransientBottomBar +import com.google.android.material.snackbar.Snackbar +import com.krunal.demo.databinding.FragmentCoordinatorLayoutBinding + +class CoordinatorLayoutFragment : Fragment() { + + private lateinit var binding: FragmentCoordinatorLayoutBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentCoordinatorLayoutBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupUI() + } + + private fun setupUI() { + setupSnackBar() + } + + private fun setupSnackBar() { + binding.btnSwipeableSnackBar.setOnClickListener { + Snackbar.make(requireView(), (it as Button).text, Snackbar.LENGTH_LONG).apply { + behavior = BaseTransientBottomBar.Behavior() + animationMode = BaseTransientBottomBar.ANIMATION_MODE_SLIDE + behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_ANY) + show() + } + } + } + +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/CustomViewFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/CustomViewFragment.kt new file mode 100644 index 0000000..04fd5cf --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/CustomViewFragment.kt @@ -0,0 +1,6 @@ +package com.krunal.demo.uicomponents + +import androidx.fragment.app.Fragment +import com.krunal.demo.R + +class CustomViewFragment : Fragment(R.layout.fragment_custom_view) \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/EditTextFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/EditTextFragment.kt new file mode 100644 index 0000000..a2eca4f --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/EditTextFragment.kt @@ -0,0 +1,67 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.util.Patterns +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import androidx.core.view.children +import androidx.core.widget.addTextChangedListener +import androidx.fragment.app.Fragment +import com.google.android.material.textfield.TextInputLayout +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentEditTextBinding +import com.krunal.demo.uicomponents.extentions.hideKeyboard + + +class EditTextFragment : Fragment(R.layout.fragment_edit_text) { + + private lateinit var binding: FragmentEditTextBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentEditTextBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupListeners() + } + + private fun setupListeners() { + binding.root.setOnFocusChangeListener { view, isFocused -> + if (isFocused) view.hideKeyboard() + } + + binding.etEmail.setOnFocusChangeListener { emailView, isFocused -> + val email = binding.etEmail.text.toString() + binding.emailContainer.error = if (!isFocused && !isValidEmail(email)) { + "Invalid email address" + } else { + null + } + } + + binding.etEmail.addTextChangedListener { + if (it?.length == 0) binding.emailContainer.error = null + } + + binding.btnClear.setOnClickListener { + binding.root.children.forEach { + if (it is EditText) { + it.text.clear() + } else if (it is TextInputLayout) { + it.editText?.text?.clear() + } + } + } + } + + private fun isValidEmail(email: String): Boolean { + val pattern = Patterns.EMAIL_ADDRESS + return pattern.matcher(email).matches() + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/FabFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/FabFragment.kt new file mode 100644 index 0000000..e935178 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/FabFragment.kt @@ -0,0 +1,69 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.google.android.material.snackbar.Snackbar +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentFabBinding + +class FabFragment : Fragment(R.layout.fragment_fab) { + + private lateinit var binding: FragmentFabBinding + private var visible: Boolean = false + private lateinit var snackBar: Snackbar + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentFabBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.fabAdd.setOnClickListener { + changeVisibility() + if (visible) snackBar.show() + } + setupExpandableFab() + setupSnackBar() + } + + private fun changeVisibility() { + visible = visible.not() + binding.fabAdd.setImageResource( + if (visible) R.drawable.ic_cross + else R.drawable.ic_add + ) + binding.fabEdit.visibility = if (visible) View.VISIBLE else View.INVISIBLE + binding.fabImage.visibility = if (visible) View.VISIBLE else View.INVISIBLE + } + + private fun setupExpandableFab() { + binding.fabExtended1.isChecked = true + binding.fabExtended2.isChecked = true + + binding.fabExtended1.addOnCheckedChangeListener { _, isChecked -> + binding.fabExtended1.isExtended = isChecked + } + + binding.fabExtended2.addOnCheckedChangeListener { _, isChecked -> + binding.fabExtended2.isExtended = isChecked + } + + binding.fabExtended3.setOnClickListener { + binding.fabExtended3.isExtended = binding.fabExtended3.isExtended.not() + } + } + + private fun setupSnackBar() { + snackBar = Snackbar.make(binding.root, "Fab button opened", Snackbar.LENGTH_SHORT) + snackBar.anchorView = binding.fabImage + snackBar.setAction("Close") { + changeVisibility() + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/FrameLayoutFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/FrameLayoutFragment.kt new file mode 100644 index 0000000..c833914 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/FrameLayoutFragment.kt @@ -0,0 +1,8 @@ +package com.krunal.demo.uicomponents + +import androidx.fragment.app.Fragment +import com.krunal.demo.R + +class FrameLayoutFragment : Fragment(R.layout.fragment_frame_layout) { + +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/LinearLayoutFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/LinearLayoutFragment.kt new file mode 100644 index 0000000..00d1a6b --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/LinearLayoutFragment.kt @@ -0,0 +1,8 @@ +package com.krunal.demo.uicomponents + +import androidx.fragment.app.Fragment +import com.krunal.demo.R + +class LinearLayoutFragment : Fragment(R.layout.fragment_linear_layout) { + +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/ProgressBarFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ProgressBarFragment.kt new file mode 100644 index 0000000..3c6a3cd --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ProgressBarFragment.kt @@ -0,0 +1,41 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.krunal.demo.databinding.FragmentProgressBarBinding +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class ProgressBarFragment : Fragment() { + + private lateinit var binding: FragmentProgressBarBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentProgressBarBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupProgress() + } + + private fun setupProgress() { + CoroutineScope(Dispatchers.Main).launch { + repeat(10) { + delay(1000) + binding.pbCircularDeterminate.incrementProgressBy(5) + binding.pbCircularIndeterminate1.incrementProgressBy(5) + binding.pbCircularIndeterminate2.incrementProgressBy(5) + binding.pbHorizontalDeterminate.incrementProgressBy(-5) + } + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/RadioFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/RadioFragment.kt new file mode 100644 index 0000000..2b1e07c --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/RadioFragment.kt @@ -0,0 +1,52 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.Fragment +import com.google.android.material.radiobutton.MaterialRadioButton +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentRadioBinding + +class RadioFragment : Fragment(R.layout.fragment_radio) { + + private lateinit var binding: FragmentRadioBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentRadioBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + showSelected() + } + + private fun showSelected() { + val toast = Toast(requireContext()) + toast.duration = Toast.LENGTH_SHORT + toast.setGravity(Gravity.CENTER_HORIZONTAL, 0, 0) + + binding.rgGender.setOnCheckedChangeListener { _, id -> + toast.setText( + when (id) { + binding.radioMale.id -> "Male" + binding.radioFemale.id -> "Female" + else -> "Other" + } + ) + toast.show() + } + binding.rgHouse.setOnCheckedChangeListener { _, id -> + toast.setText( + binding.root.findViewById(id).text + ) + toast.show() + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/RelativeLayoutFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/RelativeLayoutFragment.kt new file mode 100644 index 0000000..871b5cf --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/RelativeLayoutFragment.kt @@ -0,0 +1,8 @@ +package com.krunal.demo.uicomponents + +import androidx.fragment.app.Fragment +import com.krunal.demo.R + +class RelativeLayoutFragment : Fragment(R.layout.fragment_relative_layout) { + +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/SliderFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SliderFragment.kt new file mode 100644 index 0000000..e79bbf7 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SliderFragment.kt @@ -0,0 +1,50 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentSliderBinding + +class SliderFragment : Fragment(R.layout.fragment_slider) { + + private lateinit var binding: FragmentSliderBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentSliderBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupBars() + } + + private fun setupBars() { + binding.sliderNormal.addOnChangeListener { _, value, _ -> + binding.tvSliderNormal.text = getString(R.string.slider_value, value) + } + + binding.sliderDiscrete.addOnChangeListener { _, value, _ -> + binding.tvSliderDiscrete.text = getString(R.string.slider_value, value) + } + + binding.sliderRange.addOnChangeListener { _, _, _ -> + val values = binding.sliderRange.values + binding.tvSliderRange.text = getString( + R.string.slider_range_value, values[0], values[1] + ) + } + + binding.sliderRangeDiscrete.addOnChangeListener { _, _, _ -> + val values = binding.sliderRangeDiscrete.values + binding.tvSliderRangeDiscrete.text = getString( + R.string.slider_range_value, values[0], values[1] + ) + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/SnackBarFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SnackBarFragment.kt new file mode 100644 index 0000000..269a034 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SnackBarFragment.kt @@ -0,0 +1,69 @@ +package com.krunal.demo.uicomponents + +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.fragment.app.Fragment +import com.google.android.material.behavior.SwipeDismissBehavior +import com.google.android.material.snackbar.BaseTransientBottomBar.ANIMATION_MODE_SLIDE +import com.google.android.material.snackbar.BaseTransientBottomBar.Behavior +import com.google.android.material.snackbar.Snackbar +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentSnackbarBinding + +class SnackBarFragment : Fragment(R.layout.fragment_snackbar) { + + private lateinit var binding: FragmentSnackbarBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentSnackbarBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupSnackBars() + } + + private fun setupSnackBars() { + binding.btnShortSnackBar.setOnClickListener { + Snackbar.make(requireView(), (it as Button).text, Snackbar.LENGTH_SHORT).show() + } + + binding.btnLongSnackBar.setOnClickListener { + Snackbar.make(requireView(), (it as Button).text, Snackbar.LENGTH_LONG).show() + } + + binding.btnMultiLineSnackBar.setOnClickListener { + Snackbar.make(requireView(), (it as Button).text, Snackbar.LENGTH_SHORT).show() + } + + binding.btnActionSnackBar.setOnClickListener { + val snackBar = Snackbar.make(requireView(), (it as Button).text, Snackbar.LENGTH_LONG) + .setBackgroundTint(Color.GRAY).setActionTextColor(Color.GREEN) + snackBar.setAction("Red") { + snackBar.setBackgroundTint(Color.RED) + } + snackBar.show() + } + + binding.btnAnchorSnackBar.setOnClickListener { + Snackbar.make(requireView(), (it as Button).text, Snackbar.LENGTH_LONG) + .setAnchorView(binding.btnShortSnackBar).show() + } + + binding.btnSwipeableSnackBar.setOnClickListener { + Snackbar.make(requireView(), (it as Button).text, Snackbar.LENGTH_LONG).apply { + behavior = Behavior() + animationMode = ANIMATION_MODE_SLIDE + behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_ANY) + show() + } + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/SpanFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SpanFragment.kt new file mode 100644 index 0000000..c392e46 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SpanFragment.kt @@ -0,0 +1,103 @@ +package com.krunal.demo.uicomponents + +import android.graphics.Color +import android.os.Bundle +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.method.LinkMovementMethod +import android.text.style.ForegroundColorSpan +import android.text.style.StrikethroughSpan +import android.text.style.URLSpan +import android.text.style.UnderlineSpan +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.core.text.bold +import androidx.core.text.italic +import androidx.core.text.toSpannable +import androidx.fragment.app.Fragment +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentSpanBinding +import com.krunal.demo.uicomponents.extentions.addTextView +import com.krunal.demo.uicomponents.views.MyClickableSpan + +class SpanFragment : Fragment() { + + private lateinit var binding: FragmentSpanBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentSpanBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupSpans() + } + + private fun setupSpans() { + // Normal foreground color span + val textNormal = binding.tvColorSpan.text + val spanNormal = textNormal.toSpannable().apply { + setSpan( + ForegroundColorSpan(Color.RED), 8, 11, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + setSpan( + ForegroundColorSpan(Color.GREEN), 16, 21, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + binding.tvColorSpan.text = spanNormal + + // Underlined and LineThrough + val textUnderlineLineThrough = binding.tvUnderlineLineThroughSpan.text + val spanUnderlineLineThrough = textUnderlineLineThrough.toSpannable().apply { + setSpan( + UnderlineSpan(), 8, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + setSpan( + StrikethroughSpan(), 23, 34, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + binding.tvUnderlineLineThroughSpan.text = spanUnderlineLineThrough + + // Clickable Link + val spanLink = SpannableStringBuilder("This is my ").bold { + italic { + append( + "Portfolio", + URLSpan("https://krunalpatel.me"), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + }.append(" or you can visit my ").bold { + italic { + append( + "Blog", + URLSpan("https://blog.krunalpatel.me"), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + } + binding.tvLink.text = spanLink + binding.tvLink.movementMethod = LinkMovementMethod.getInstance() + + // Clickable span + val clickableText = "You can click on any word" + + SpannableStringBuilder().also { spanBuilder -> + clickableText.split(" ").forEach { word -> + spanBuilder.append("$word ", MyClickableSpan { + Toast.makeText( + requireContext(), + getString(R.string.click_toast_text, word), + Toast.LENGTH_SHORT + ).show() + }, Spannable.SPAN_INCLUSIVE_EXCLUSIVE) + } + binding.root.addTextView(spanBuilder) + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/SpinnerFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SpinnerFragment.kt new file mode 100644 index 0000000..3f4b669 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/SpinnerFragment.kt @@ -0,0 +1,64 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.Toast +import androidx.fragment.app.Fragment +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentSpinnerBinding +import com.krunal.demo.uicomponents.adapters.TimezoneAdapter + +class SpinnerFragment : Fragment(), AdapterView.OnItemSelectedListener { + + private lateinit var binding: FragmentSpinnerBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentSpinnerBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupSpinners() + } + + private fun setupSpinners() { + ArrayAdapter.createFromResource( + requireContext(), R.array.timezones, android.R.layout.simple_spinner_item + ).also { adapter -> + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + binding.spinnerNormal.adapter = adapter + binding.spinnerDialog.adapter = adapter + binding.spinnerUnderlined.adapter = adapter + binding.spinnerBordered.adapter = adapter + binding.autoCompleteTimezone.setAdapter(adapter) + binding.spinnerDisabled.adapter = adapter + } + + binding.spinnerBordered.setSelection(4, true) + binding.spinnerNormal.onItemSelectedListener = this + binding.spinnerDisabled.isEnabled = false + + val adapter = TimezoneAdapter(requireContext(), resources.getStringArray(R.array.timezones)) + binding.spinnerCustom.adapter = adapter + } + + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + Toast.makeText( + requireContext(), + binding.spinnerNormal.selectedItem.toString(), + Toast.LENGTH_SHORT + ).show() + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + Toast.makeText(requireContext(), getString(R.string.nothing_selected), Toast.LENGTH_SHORT) + .show() + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/TabLayoutFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/TabLayoutFragment.kt new file mode 100644 index 0000000..838a944 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/TabLayoutFragment.kt @@ -0,0 +1,41 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentTabLayoutBinding +import com.krunal.demo.uicomponents.adapters.ViewPagerAdapter + +class TabLayoutFragment : Fragment(R.layout.fragment_tab_layout) { + + private lateinit var binding: FragmentTabLayoutBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentTabLayoutBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupTabsWithPager() + } + + private fun setupTabsWithPager() { + val viewPagerAdapter = ViewPagerAdapter(requireActivity()) + binding.viewPager.adapter = viewPagerAdapter + TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position -> + tab.text = when (position) { + 0 -> "Home" + 1 -> "Chat" + else -> "Call" + } + }.attach() + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/ThemeFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ThemeFragment.kt new file mode 100644 index 0000000..7fc27ed --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ThemeFragment.kt @@ -0,0 +1,57 @@ +package com.krunal.demo.uicomponents + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope +import com.krunal.demo.databinding.FragmentThemeBinding +import com.krunal.demo.uicomponents.adapters.ThemeAdapter +import com.krunal.demo.uicomponents.extentions.isDarkMode +import com.krunal.demo.uicomponents.helpers.ThemeHelper +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class ThemeFragment : Fragment() { + + private lateinit var binding: FragmentThemeBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentThemeBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupTheme() + } + + private fun setupTheme() { + val themes = ThemeHelper.getThemes(requireContext(), requireActivity().isDarkMode) + val themeAdapter = ThemeAdapter( + requireContext(), themes + ) + + binding.gvTheme.adapter = themeAdapter + binding.gvTheme.setItemChecked(ThemeHelper.getThemeAccent().ordinal, true) + lifecycleScope.launch { + delay(100) + + binding.gvTheme.setItemChecked(ThemeHelper.getThemeAccent().ordinal, true) + binding.gvTheme.setSelection(ThemeHelper.getThemeAccent().ordinal) + Log.d("Tag", ThemeHelper.getThemeAccent().ordinal.toString()) + Log.d("Tag", binding.gvTheme.selectedItemPosition.toString()) + } + // binding.gvTheme.selectedView.performClick() // selectedView is null + + binding.gvTheme.setOnItemClickListener { _, _, position, _ -> + ThemeHelper.setThemeAccent(themes[position].accentColor) + // TODO: Restart activity +// activity?.recreate() + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/ToastFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ToastFragment.kt new file mode 100644 index 0000000..b6822f5 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/ToastFragment.kt @@ -0,0 +1,74 @@ +package com.krunal.demo.uicomponents + +import android.graphics.Color +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import android.widget.Toast +import androidx.core.content.res.ResourcesCompat +import androidx.fragment.app.Fragment +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentToastBinding + +class ToastFragment : Fragment(R.layout.fragment_toast) { + private lateinit var binding: FragmentToastBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentToastBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupButtons() + } + + // Set click listeners for buttons to show toast + private fun setupButtons() { + // Short toast + binding.btnShortToast.setOnClickListener { + Toast.makeText(requireContext(), "This is short Toast", Toast.LENGTH_SHORT).show() + } + + // Long toast + binding.btnLongToast.setOnClickListener { + Toast.makeText(requireContext(), "This is long Toast", Toast.LENGTH_LONG).show() + } + + // Custom short success toast + binding.btnSuccessToast.setOnClickListener { + showToast(R.drawable.ic_check, "Custom success toast", backgroundColor = Color.GREEN) + } + + // Custom long error toast + binding.btnErrorToast.setOnClickListener { + showToast(R.drawable.ic_cross, "Custom error toast", Toast.LENGTH_LONG, Color.RED) + } + } + + // Make and show custom toast + private fun showToast(iconId: Int, text: String, length: Int = Toast.LENGTH_SHORT, backgroundColor: Int = Color.GRAY) { + val toastView = layoutInflater.inflate(R.layout.custom_toast, requireActivity().findViewById(R.id.customToast)) + val imgViewStatus = toastView.findViewById(R.id.imgViewStatus) + val tvMessage = toastView.findViewById(R.id.tvMessage) + + toastView.setBackgroundColor(backgroundColor) + imgViewStatus.setImageResource(iconId) + tvMessage.text = text + + Toast(requireContext()).apply { + setGravity(Gravity.CENTER, 0, 0) + duration = length + view = toastView + show() + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ThemeAdapter.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ThemeAdapter.kt new file mode 100644 index 0000000..81716d3 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ThemeAdapter.kt @@ -0,0 +1,33 @@ +package com.krunal.demo.uicomponents.adapters + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.TextView +import com.google.android.material.card.MaterialCardView +import com.krunal.demo.R +import com.krunal.demo.uicomponents.models.Theme + +class ThemeAdapter( + private val context: Context, + private val themes: List +) : BaseAdapter() { + override fun getCount(): Int = themes.size + + override fun getItem(position: Int): Any? = null + + override fun getItemId(position: Int): Long = 0 + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val inflater = LayoutInflater.from(context) + val view = inflater.inflate(R.layout.theme_layout, null) + val tvName = view.findViewById(R.id.tvThemeName) + val viewTheme = view.findViewById(R.id.cardThemeColor) + + tvName.text = themes[position].name + viewTheme.setCardBackgroundColor(themes[position].color) + return view + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/TimezoneAdapter.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/TimezoneAdapter.kt new file mode 100644 index 0000000..4f445da --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/TimezoneAdapter.kt @@ -0,0 +1,29 @@ +package com.krunal.demo.uicomponents.adapters + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.TextView +import com.krunal.demo.R + +class TimezoneAdapter(private val context: Context, private val timezones: Array): BaseAdapter() { + + override fun getCount() = timezones.size + + override fun getItem(position: Int) = null + + override fun getItemId(position: Int): Long = 0 + + @SuppressLint("ViewHolder") + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val inflater = LayoutInflater.from(context) + val view = inflater.inflate(R.layout.timezone_spinner, null) + val tvName = view.findViewById(R.id.tvTimezone) + tvName.text = timezones[position] + + return view + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ViewBindingAdapter.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ViewBindingAdapter.kt new file mode 100644 index 0000000..548048c --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ViewBindingAdapter.kt @@ -0,0 +1,61 @@ +package com.krunal.demo.uicomponents.adapters + +import android.graphics.Color +import android.graphics.drawable.GradientDrawable +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.appcompat.content.res.AppCompatResources +import androidx.core.graphics.ColorUtils +import androidx.databinding.BindingAdapter + +@BindingAdapter("drawableResource") +fun ImageView.setDrawableResource(@DrawableRes drawableResource: Int) { + setImageResource(drawableResource) +} + +@BindingAdapter("drawableResource") +fun TextView.setStartDrawableResource(@DrawableRes drawableResource: Int) { + setCompoundDrawablesRelativeWithIntrinsicBounds( + AppCompatResources.getDrawable(context, drawableResource), null, null, null + ) +} + +@BindingAdapter("drawableColorResource") +fun TextView.setStartColorResource(@ColorRes colorResource: Int) { + compoundDrawablesRelative.filterNotNull().forEach { drawable -> + drawable.mutate().setTint(resources.getColor(colorResource, context.theme)) + } +} + +@BindingAdapter("textColorResource") +fun TextView.setTextColorResource(@ColorRes colorResource: Int) { + setTextColor(resources.getColor(colorResource, context.theme)) +} + +@BindingAdapter("textColor") +fun TextView.setTextColor(color: Int) { + setTextColor(color) +} + +@BindingAdapter("backgroundColor") +fun View.setViewBackgroundColor(color: Int) { + setBackgroundColor(color) +} + +@BindingAdapter("gradientStartColor", "gradientEndColor", "angle", requireAll = false) +fun View.setGradientBackground(gradientStartColor: Int?, gradientEndColor: Int?, angle: Int?) { + gradientStartColor?.let { it -> + ColorUtils.setAlphaComponent(it, 0x4f).let { color -> + GradientDrawable( + GradientDrawable.Orientation.TR_BL, + intArrayOf(color, gradientEndColor ?: Color.TRANSPARENT) + ).also { + it.cornerRadius = 0f + background = it + } + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ViewPagerAdapter.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ViewPagerAdapter.kt new file mode 100644 index 0000000..b88918c --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/adapters/ViewPagerAdapter.kt @@ -0,0 +1,16 @@ +package com.krunal.demo.uicomponents.adapters + +import androidx.fragment.app.FragmentActivity +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.krunal.demo.uicomponents.tablayoutfragments.CallsFragment +import com.krunal.demo.uicomponents.tablayoutfragments.ChatFragment +import com.krunal.demo.uicomponents.tablayoutfragments.HomeFragment + +class ViewPagerAdapter(fa: FragmentActivity): FragmentStateAdapter(fa) { + + private val fragments = listOf(HomeFragment(), ChatFragment(), CallsFragment()) + + override fun getItemCount() = fragments.count() + + override fun createFragment(position: Int) = fragments[position] +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/binding/DataBindingFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/binding/DataBindingFragment.kt new file mode 100644 index 0000000..c89d361 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/binding/DataBindingFragment.kt @@ -0,0 +1,26 @@ +package com.krunal.demo.uicomponents.binding + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import com.krunal.demo.databinding.FragmentDataBindingBinding + +class DataBindingFragment : Fragment() { + + private lateinit var binding: FragmentDataBindingBinding + private val viewModel: DataBingingViewModel by viewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentDataBindingBinding.inflate(inflater) + binding.viewModel = viewModel + binding.lifecycleOwner = viewLifecycleOwner + return binding.root + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/binding/DataBingingViewModel.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/binding/DataBingingViewModel.kt new file mode 100644 index 0000000..ced1218 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/binding/DataBingingViewModel.kt @@ -0,0 +1,34 @@ +package com.krunal.demo.uicomponents.binding + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.krunal.demo.uicomponents.models.Name +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch + +class DataBingingViewModel : ViewModel() { + + private val _nameFlow = MutableStateFlow(null) + val nameFlow: StateFlow = _nameFlow + + init { + randomName() + } + + /** Generate and emmit random names to [nameFlow] */ + private fun randomName() { + // List of random names + val names = listOf( + Name("Harry", "Potter") + ) + + viewModelScope.launch { + while (true) { + delay(3000) + _nameFlow.emit(names.first()) + } + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/cardscreen/CardFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/cardscreen/CardFragment.kt new file mode 100644 index 0000000..f296686 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/cardscreen/CardFragment.kt @@ -0,0 +1,117 @@ +package com.krunal.demo.uicomponents.cardscreen + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import com.google.android.material.chip.Chip +import com.google.android.material.navigation.NavigationBarView +import com.krunal.demo.R +import com.krunal.demo.UIComponentsActivity +import com.krunal.demo.databinding.CardLayoutBinding +import com.krunal.demo.databinding.FragmentCardBinding +import com.krunal.demo.uicomponents.dialogs.MyDatePickerDialog +import com.krunal.demo.uicomponents.extentions.dpFormat +import com.krunal.demo.uicomponents.models.CardDetail +import com.krunal.demo.uicomponents.sheets.OperationsBottomSheetFragment +import kotlinx.coroutines.launch + +class CardFragment : Fragment() { + + private lateinit var binding: FragmentCardBinding + private val viewModel: CardFragmentViewModel by viewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentCardBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupUI() + } + + private fun setupUI() { + setupBottomBar() + (activity as? UIComponentsActivity)?.supportActionBar?.apply { + title = getString(R.string.my_cards) + setBackgroundDrawable(ColorDrawable(Color.parseColor("#2F7CEF"))) + elevation = 0f + // TODO: Make title center + } + + setupCardChips() + + setupCard() + + binding.cardOperations.btnDetails.setOnClickListener { + OperationsBottomSheetFragment().show(childFragmentManager, null) + } + + binding.cardOperations.btnCalendar.setOnClickListener { + MyDatePickerDialog().show(childFragmentManager, null) + } + } + + private fun setupCardChips() { + viewModel.dummyCardDetails.forEach { card -> + (layoutInflater.inflate(R.layout.card_chip, null) as? Chip)?.apply { + text = getString(R.string.card_name, card.type, card.number) + isChecked = card.isSelected + setOnCheckedChangeListener { _, isChecked -> + viewModel.updateCardSelection( + card, + isChecked + ) + } + }.also { cardChip -> + binding.cgCard.addView(cardChip) + } + } + } + + private fun setupCard() { + addSelectedCards(viewModel.dummyCardDetails) + lifecycleScope.launch { + viewModel.selectedCards.collect { cardList -> + binding.llCards.removeViews(1, binding.llCards.childCount - 1) + addSelectedCards(cardList) + } + } + } + + private fun addSelectedCards(cardList: List) { + cardList + .filter { it.isSelected } + .forEach { card -> + val cardBinding = CardLayoutBinding.inflate(layoutInflater) + cardBinding.card = card + + val layoutParams = LinearLayout.LayoutParams( + 300.dpFormat(requireContext()), + 200.dpFormat(requireContext()), + ).apply { + marginEnd = 18.dpFormat(requireContext()) + } + + cardBinding.root.layoutParams = layoutParams + binding.llCards.addView(cardBinding.root) + } + } + + private fun setupBottomBar() { + binding.bottomNavigation.apply { + selectedItemId = menu.getItem(1).itemId + labelVisibilityMode = NavigationBarView.LABEL_VISIBILITY_SELECTED + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/cardscreen/CardFragmentViewModel.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/cardscreen/CardFragmentViewModel.kt new file mode 100644 index 0000000..2c76f8e --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/cardscreen/CardFragmentViewModel.kt @@ -0,0 +1,29 @@ +package com.krunal.demo.uicomponents.cardscreen + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.krunal.demo.uicomponents.models.CardDetail +import com.krunal.demo.uicomponents.models.enums.CardType +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.launch + +class CardFragmentViewModel : ViewModel() { + + private val _selectedCards = MutableSharedFlow>() + val selectedCards: SharedFlow> = _selectedCards + + var dummyCardDetails: List = buildList { + add(CardDetail(CardType.DEBIT, 1963, "$2,983.78", true)) + add(CardDetail(CardType.DEBIT, 1822, "$1,002.02")) + add(CardDetail(CardType.CREDIT, 2291, "$540.00")) + } + + fun updateCardSelection(card: CardDetail, isSelected: Boolean) { + dummyCardDetails.find { it.number == card.number }?.isSelected = + isSelected + viewModelScope.launch { + _selectedCards.emit(dummyCardDetails) + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/ChainBiasFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/ChainBiasFragment.kt new file mode 100644 index 0000000..dfb8893 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/ChainBiasFragment.kt @@ -0,0 +1,5 @@ +package com.krunal.demo.uicomponents.constraintLayouts + +import androidx.fragment.app.Fragment + +class ChainBiasFragment : Fragment() \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/CircularFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/CircularFragment.kt new file mode 100644 index 0000000..2f8fbe6 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/CircularFragment.kt @@ -0,0 +1,32 @@ +package com.krunal.demo.uicomponents.constraintLayouts + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentClCircularBinding + +class CircularFragment : Fragment(R.layout.fragment_cl_circular) { + + private lateinit var binding: FragmentClCircularBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentClCircularBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupUI() + } + + private fun setupUI() { + binding.imgBtnMain.setOnCheckedChangeListener { _, isChecked -> + binding.groupEmojis.visibility = if (isChecked) View.VISIBLE else View.INVISIBLE + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/GuidelineBarrierFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/GuidelineBarrierFragment.kt new file mode 100644 index 0000000..64d7c05 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/GuidelineBarrierFragment.kt @@ -0,0 +1,5 @@ +package com.krunal.demo.uicomponents.constraintLayouts + +import androidx.fragment.app.Fragment + +class GuidelineBarrierFragment : Fragment() \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/RelativeFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/RelativeFragment.kt new file mode 100644 index 0000000..18dac3a --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/constraintLayouts/RelativeFragment.kt @@ -0,0 +1,6 @@ +package com.krunal.demo.uicomponents.constraintLayouts + +import androidx.fragment.app.Fragment +import com.krunal.demo.R + +class RelativeFragment : Fragment(R.layout.fragment_cl_relative) \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/dialogs/MyDatePickerDialog.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/dialogs/MyDatePickerDialog.kt new file mode 100644 index 0000000..369e675 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/dialogs/MyDatePickerDialog.kt @@ -0,0 +1,21 @@ +package com.krunal.demo.uicomponents.dialogs + +import android.app.DatePickerDialog +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import java.util.Calendar + +class MyDatePickerDialog : DialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val mCalendar: Calendar = Calendar.getInstance() + val year = mCalendar.get(Calendar.YEAR) + val month = mCalendar.get(Calendar.MONTH) + val dayOfMonth = mCalendar.get(Calendar.DAY_OF_MONTH) + + return DatePickerDialog(requireActivity(), null, year, month, dayOfMonth).apply { + datePicker.maxDate = Calendar.getInstance().timeInMillis + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/ActivityExtentions.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/ActivityExtentions.kt new file mode 100644 index 0000000..36b32d9 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/ActivityExtentions.kt @@ -0,0 +1,21 @@ +package com.krunal.demo.uicomponents.extentions + +import android.app.Activity +import android.content.Context +import android.content.res.Configuration +import android.util.TypedValue + + +fun Context.getThemeColor(resId: Int): Int { + val typedValue = TypedValue() + theme.resolveAttribute(resId, typedValue, true) + return typedValue.data +} + +val Activity.isDarkMode: Boolean + get() = when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { + Configuration.UI_MODE_NIGHT_YES -> true + Configuration.UI_MODE_NIGHT_NO -> false + Configuration.UI_MODE_NIGHT_UNDEFINED -> false + else -> false + } \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/LinearLayoutExtentions.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/LinearLayoutExtentions.kt new file mode 100644 index 0000000..4ee254f --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/LinearLayoutExtentions.kt @@ -0,0 +1,29 @@ +package com.krunal.demo.uicomponents.extentions + +import android.text.Spanned +import android.text.method.LinkMovementMethod +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.text.toSpanned + +// Add text to the LinearLayout by creating new TextView +fun LinearLayout.addTextView(text: String) { + addTextView(text.toSpanned()) +} + +// Add spanned text to the LinearLayout by creating new TextView +fun LinearLayout.addTextView(spanText: Spanned) { + TextView(context).apply { + layoutParams = LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT, + ).apply { + topMargin = 24.dpFormat(context) + } + text = spanText + textSize = 18f + movementMethod = LinkMovementMethod.getInstance() + }.also { textView -> + addView(textView) + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/NumberExtentions.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/NumberExtentions.kt new file mode 100644 index 0000000..43bc8c3 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/NumberExtentions.kt @@ -0,0 +1,10 @@ +package com.krunal.demo.uicomponents.extentions + +import android.content.Context +import android.util.DisplayMetrics +import kotlin.math.roundToInt + +fun Int.dpFormat(context: Context): Int { + val displayMetrics = context.resources.displayMetrics + return (this * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)).roundToInt() +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/TypedArrayExtentions.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/TypedArrayExtentions.kt new file mode 100644 index 0000000..9e6af51 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/TypedArrayExtentions.kt @@ -0,0 +1,15 @@ +package com.krunal.demo.uicomponents.extentions + +import android.content.res.TypedArray + +fun TypedArray.toFloat(): List = buildList { + for (i in 0 until length()) { + add(getFloat(i, -1f)) + } +} + +fun TypedArray.toInt(): List = buildList { + for (i in 0 until length()) { + add(getInt(i, -1)) + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/ViewExtentions.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/ViewExtentions.kt new file mode 100644 index 0000000..856ac34 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/extentions/ViewExtentions.kt @@ -0,0 +1,10 @@ +package com.krunal.demo.uicomponents.extentions + +import android.app.Activity +import android.view.View +import android.view.inputmethod.InputMethodManager + +fun View.hideKeyboard() { + val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager + inputMethodManager.hideSoftInputFromWindow(windowToken, 0) +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/helpers/PreferenceHelper.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/helpers/PreferenceHelper.kt new file mode 100644 index 0000000..4c7cca8 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/helpers/PreferenceHelper.kt @@ -0,0 +1,69 @@ +package com.krunal.demo.uicomponents.helpers + +import android.content.Context +import android.content.SharedPreferences +import androidx.preference.PreferenceManager + +object PreferenceHelper { + + private lateinit var preferences: SharedPreferences + private lateinit var editor: SharedPreferences.Editor + + /** + * set the context that is being used to access the shared preferences + */ + fun initialize(context: Context) { + preferences = getDefaultSharedPreferences(context) + editor = preferences.edit() + } + + fun putString(key: String, value: String) { + editor.putString(key, value).commit() + } + + fun putBoolean(key: String, value: Boolean) { + editor.putBoolean(key, value).commit() + } + + fun putInt(key: String, value: Int) { + editor.putInt(key, value).commit() + } + + fun putFloat(key: String, value: Float) { + editor.putFloat(key, value).commit() + } + + fun putLong(key: String, value: Long) { + editor.putLong(key, value).commit() + } + + fun getString(key: String?, defValue: String): String { + return preferences.getString(key, defValue) ?: defValue + } + + fun getBoolean(key: String?, defValue: Boolean): Boolean { + return preferences.getBoolean(key, defValue) + } + + fun getInt(key: String?, defValue: Int): Int { + return runCatching { + preferences.getInt(key, defValue) + }.getOrElse { preferences.getLong(key, defValue.toLong()).toInt() } + } + + fun getLong(key: String?, defValue: Long): Long { + return preferences.getLong(key, defValue) + } + + fun getFloat(key: String?, defValue: Float): Float { + return preferences.getFloat(key, defValue) + } + + fun clearPreferences() { + editor.clear().apply() + } + + private fun getDefaultSharedPreferences(context: Context): SharedPreferences { + return PreferenceManager.getDefaultSharedPreferences(context) + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/helpers/ThemeHelper.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/helpers/ThemeHelper.kt new file mode 100644 index 0000000..2bedaae --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/helpers/ThemeHelper.kt @@ -0,0 +1,79 @@ +package com.krunal.demo.uicomponents.helpers + +import android.content.Context +import com.krunal.demo.R +import com.krunal.demo.uicomponents.models.Theme +import com.krunal.demo.uicomponents.models.enums.AccentColor +import com.krunal.demo.uicomponents.models.enums.ThemeMode +import com.krunal.demo.uicomponents.utils.PreferenceKeys + +object ThemeHelper { + fun getThemes(context: Context, isDark: Boolean = false): List { + val accentValues = AccentColor.values() + val accent = context.resources.getStringArray(R.array.accents) + + return buildList { + for (i in accentValues.indices) { + add( + Theme( + accent[i], accentValues[i], getAccentColor(context, accentValues[i], isDark) + ) + ) + } + } + } + + fun getThemeResource(accentColor: AccentColor): Int { + return when (accentColor) { + AccentColor.RED -> R.style.Theme_Red + AccentColor.BLUE -> R.style.Theme_Blue + AccentColor.YELLOW -> R.style.Theme_Yellow + AccentColor.GREEN -> R.style.Theme_Green + AccentColor.PURPLE -> R.style.Theme_Purple + AccentColor.VIOLET -> R.style.Theme_Violet + } + } + + fun getThemeMode(): ThemeMode { + return ThemeMode.valueOf( + PreferenceHelper.getString( + PreferenceKeys.THEME_MODE, + ThemeMode.AUTO.name + ) + ) + } + + fun setThemeMode(mode: ThemeMode) { + PreferenceHelper.putString(PreferenceKeys.THEME_MODE, mode.name) + } + + fun getThemeAccent(): AccentColor { + return AccentColor.valueOf( + PreferenceHelper.getString( + PreferenceKeys.ACCENT_COLOR, + AccentColor.VIOLET.name + ) + ) + } + + fun setThemeAccent(color: AccentColor) { + PreferenceHelper.putString(PreferenceKeys.ACCENT_COLOR, color.name) + } + + private fun getAccentColor( + context: Context, + accentColor: AccentColor, + isDarkMode: Boolean + ): Int { + return context.getColor( + when (accentColor) { + AccentColor.RED -> if (isDarkMode) R.color.red_md_theme_dark_primary else R.color.red_md_theme_light_primary + AccentColor.BLUE -> if (isDarkMode) R.color.blue_md_theme_dark_primary else R.color.blue_md_theme_light_primary + AccentColor.YELLOW -> if (isDarkMode) R.color.yellow_md_theme_dark_primary else R.color.yellow_md_theme_light_primary + AccentColor.GREEN -> if (isDarkMode) R.color.green_md_theme_dark_primary else R.color.green_md_theme_light_primary + AccentColor.PURPLE -> if (isDarkMode) R.color.purple_md_theme_dark_primary else R.color.purple_md_theme_light_primary + AccentColor.VIOLET -> if (isDarkMode) R.color.violet_theme_dark_primary else R.color.violet_theme_light_primary + } + ) + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/CardDetail.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/CardDetail.kt new file mode 100644 index 0000000..d910dbf --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/CardDetail.kt @@ -0,0 +1,18 @@ +package com.krunal.demo.uicomponents.models + +import com.krunal.demo.uicomponents.models.enums.CardType + +data class CardDetail( + val type: CardType, val number: Int, val amount: String = "$0" +) { + + var isSelected: Boolean = false + + constructor(type: CardType, number: Int, amount: String, isSelected: Boolean) : this( + type, + number, + amount + ) { + this.isSelected = isSelected + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/DrawableResource.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/DrawableResource.kt new file mode 100644 index 0000000..9f3f4fb --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/DrawableResource.kt @@ -0,0 +1,8 @@ +package com.krunal.demo.uicomponents.models + +import android.graphics.Bitmap as AndroidBitmap + +sealed interface DrawableResource { + data class Drawable(val id: Int): DrawableResource + data class Bitmap(val bitmap: AndroidBitmap): DrawableResource +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/Name.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/Name.kt new file mode 100644 index 0000000..cb56627 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/Name.kt @@ -0,0 +1,3 @@ +package com.krunal.demo.uicomponents.models + +data class Name(val firstName: String, val lastName: String) diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/Theme.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/Theme.kt new file mode 100644 index 0000000..400d7fa --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/Theme.kt @@ -0,0 +1,11 @@ +package com.krunal.demo.uicomponents.models + +import androidx.annotation.ColorRes +import com.krunal.demo.uicomponents.models.enums.AccentColor + +data class Theme( + val name: String, + val accentColor: AccentColor, + val color: Int, + val isDarkMode: Boolean = false +) diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/AccentColor.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/AccentColor.kt new file mode 100644 index 0000000..944286c --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/AccentColor.kt @@ -0,0 +1,5 @@ +package com.krunal.demo.uicomponents.models.enums + +enum class AccentColor { + RED, BLUE, YELLOW, GREEN, PURPLE, VIOLET +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/CardType.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/CardType.kt new file mode 100644 index 0000000..d3ac2a3 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/CardType.kt @@ -0,0 +1,11 @@ +package com.krunal.demo.uicomponents.models.enums + +import java.util.Locale + +enum class CardType { + DEBIT, CREDIT; + + override fun toString(): String { + return name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/ThemeMode.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/ThemeMode.kt new file mode 100644 index 0000000..4b7b2f5 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/models/enums/ThemeMode.kt @@ -0,0 +1,5 @@ +package com.krunal.demo.uicomponents.models.enums + +enum class ThemeMode { + AUTO, DARK, LIGHT +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/picker/DatePickerFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/picker/DatePickerFragment.kt new file mode 100644 index 0000000..0c78ada --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/picker/DatePickerFragment.kt @@ -0,0 +1,31 @@ +package com.krunal.demo.uicomponents.picker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.krunal.demo.databinding.FragmentDatePickerBinding +import java.util.Date + +class DatePickerFragment : Fragment() { + + private lateinit var binding: FragmentDatePickerBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentDatePickerBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupPicker() + } + + private fun setupPicker() { + binding.dpCalender.maxDate = Date().time + binding.dpCalender.updateDate(2023, 1, 1) + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/picker/TimePickerFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/picker/TimePickerFragment.kt new file mode 100644 index 0000000..8f99181 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/picker/TimePickerFragment.kt @@ -0,0 +1,62 @@ +package com.krunal.demo.uicomponents.picker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TimePicker +import android.widget.TimePicker.OnTimeChangedListener +import androidx.fragment.app.Fragment +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentTimePickerBinding + +class TimePickerFragment : Fragment(), OnTimeChangedListener { + + private lateinit var binding: FragmentTimePickerBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentTimePickerBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupPicker() + } + + private fun setupPicker() { + // Set is 24 hour format + binding.switch24hour.setOnCheckedChangeListener { _, isChecked -> + binding.tpClock.setIs24HourView(isChecked) + binding.tpSpinner.setIs24HourView(isChecked) + } + + binding.tpClock.setOnTimeChangedListener(this) + binding.tpSpinner.setOnTimeChangedListener(this) + } + + override fun onTimeChanged(timePicker: TimePicker, hourOfDay: Int, minute: Int) { + // Sync both time pickers + if (timePicker == binding.tpClock) { + binding.tpSpinner.hour = hourOfDay + binding.tpSpinner.minute = minute + } else { + binding.tpClock.hour = hourOfDay + binding.tpClock.minute = minute + } + + // Update time text view + binding.tvTime.text = if (timePicker.is24HourView) { + getString(R.string.time, hourOfDay, minute, "") + } else { + getString( + R.string.time, + if (hourOfDay % 12 == 0) 12 else hourOfDay, + minute, + if (hourOfDay < 12) "AM" else "PM" + ) + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/sheets/OperationsBottomSheetFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/sheets/OperationsBottomSheetFragment.kt new file mode 100644 index 0000000..693b651 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/sheets/OperationsBottomSheetFragment.kt @@ -0,0 +1,35 @@ +package com.krunal.demo.uicomponents.sheets + +import android.annotation.SuppressLint +import android.app.Dialog +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.krunal.demo.databinding.FragmentOperationsBottomSheetBinding + +class OperationsBottomSheetFragment : BottomSheetDialogFragment() { + + private lateinit var binding: FragmentOperationsBottomSheetBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentOperationsBottomSheetBinding.inflate(layoutInflater) + return binding.root + } + + @SuppressLint("RestrictedApi", "VisibleForTests") + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = super.onCreateDialog(savedInstanceState) + + (dialog as BottomSheetDialog).behavior.apply { + isDraggable = true + state = BottomSheetBehavior.STATE_EXPANDED + } + return dialog + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/CallsFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/CallsFragment.kt new file mode 100644 index 0000000..9c9e82c --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/CallsFragment.kt @@ -0,0 +1,6 @@ +package com.krunal.demo.uicomponents.tablayoutfragments + +import androidx.fragment.app.Fragment +import com.krunal.demo.R + +class CallsFragment : Fragment(R.layout.fragment_calls) \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/ChatFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/ChatFragment.kt new file mode 100644 index 0000000..9d9f346 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/ChatFragment.kt @@ -0,0 +1,11 @@ +package com.krunal.demo.uicomponents.tablayoutfragments + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.krunal.demo.R + +class ChatFragment : Fragment(R.layout.fragment_chat) { +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/HomeFragment.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/HomeFragment.kt new file mode 100644 index 0000000..8d124ab --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/tablayoutfragments/HomeFragment.kt @@ -0,0 +1,66 @@ +package com.krunal.demo.uicomponents.tablayoutfragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayout.OnTabSelectedListener +import com.krunal.demo.R +import com.krunal.demo.databinding.FragmentHomeBinding + +class HomeFragment : Fragment(R.layout.fragment_home) { + + private lateinit var binding: FragmentHomeBinding + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = FragmentHomeBinding.inflate(layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupTabs() + } + + private fun setupTabs() { + // Text tabs programmatically + listOf("Tab1", "Tab2", "Tab3", "Tab4").forEach { + binding.tabLayoutText.apply { + addTab(newTab().setText(it)) + } + } + + // Show/Hide lable + binding.tabLayoutSelectedText.apply { + for (i in 0..tabCount) { + if (i != selectedTabPosition) { + getTabAt(i)?.tabLabelVisibility = TabLayout.TAB_LABEL_VISIBILITY_UNLABELED + } + } + } + binding.tabLayoutSelectedText.addOnTabSelectedListener(object : OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab?) { + tab?.tabLabelVisibility = TabLayout.TAB_LABEL_VISIBILITY_LABELED + } + + override fun onTabUnselected(tab: TabLayout.Tab?) { + tab?.tabLabelVisibility = TabLayout.TAB_LABEL_VISIBILITY_UNLABELED + } + + override fun onTabReselected(tab: TabLayout.Tab?) { + + } + }) + + // Scrollable tabs + listOf("Tab1", "Tab2", "Tab3").forEach { + binding.tabLayoutScrollable.apply { + addTab(newTab().setText(it)) + } + } + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/utils/PreferenceKeys.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/utils/PreferenceKeys.kt new file mode 100644 index 0000000..70f4061 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/utils/PreferenceKeys.kt @@ -0,0 +1,11 @@ +package com.krunal.demo.uicomponents.utils + +object PreferenceKeys { + + /** + * Appearance + */ + const val THEME_MODE = "theme_mode" + const val ACCENT_COLOR = "accent_color" + +} diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/CustomView.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/CustomView.kt new file mode 100644 index 0000000..02e24ce --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/CustomView.kt @@ -0,0 +1,41 @@ +package com.krunal.demo.uicomponents.views + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.util.AttributeSet +import android.view.View +import com.krunal.demo.R + +class CustomView(context: Context, attrs: AttributeSet): View(context, attrs) { + + private val paint = Paint() + private var centerOfX = 340F + private var centerOfY = 340F + private val radiusOfCircleView = 140F + private var isCenter = false + + init { + val attributeArray: TypedArray = context.theme.obtainStyledAttributes( + attrs, R.styleable.CustomButton, 0, 0 + ) + + paint.apply { + color = attributeArray.getColor(R.styleable.CustomButton_circleColor, Color.RED) + strokeWidth = attributeArray.getFloat(R.styleable.CustomButton_strokeSize, 20f) + style = Paint.Style.STROKE + } + isCenter = attributeArray.getBoolean(R.styleable.CustomButton_onCenter, isCenter) + } + + override fun onDraw(canvas: Canvas?) { + if (isCenter) { + centerOfX = (width / 2).toFloat() + centerOfY = (height / 2).toFloat() + } + canvas?.drawCircle(centerOfX, centerOfY, radiusOfCircleView, paint) + super.onDraw(canvas) + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/HistoryLineView.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/HistoryLineView.kt new file mode 100644 index 0000000..3fd28d1 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/HistoryLineView.kt @@ -0,0 +1,70 @@ +package com.krunal.demo.uicomponents.views + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.util.AttributeSet +import android.view.View +import com.krunal.demo.R + +class HistoryLineView(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val thumbPaint = Paint(Paint.ANTI_ALIAS_FLAG) + private val linePaint = Paint(Paint.ANTI_ALIAS_FLAG) + private var thumbColor = Color.BLUE + private var lineColor = thumbColor + private var thumbRadius = 10F + private var lineWidth = 2F + + init { + + setupAttributes(attrs) + setupPaint() + } + + private fun setupAttributes(attrs: AttributeSet) { + val typedArray = + context.theme.obtainStyledAttributes(attrs, R.styleable.HistoryLineView, 0, 0) + thumbColor = typedArray.getColor(R.styleable.HistoryLineView_thumbColor, thumbColor) + lineColor = typedArray.getColor(R.styleable.HistoryLineView_lineColor, lineColor) + thumbRadius = typedArray.getDimension(R.styleable.HistoryLineView_thumbRadius, thumbRadius) + lineWidth = typedArray.getDimension(R.styleable.HistoryLineView_lineWidth, lineWidth) + +// typedArray.recycle() + } + + private fun setupPaint() { + thumbPaint.apply { + color = thumbColor + style = Paint.Style.FILL + } + + linePaint.apply { + color = lineColor + strokeWidth = lineWidth + style = Paint.Style.STROKE + strokeCap = Paint.Cap.ROUND + } + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + drawThumb(canvas) + drawLine(canvas) + } + + private fun drawThumb(canvas: Canvas) { + canvas.drawCircle((width / 2).toFloat(), thumbRadius, thumbRadius, thumbPaint) + } + + private fun drawLine(canvas: Canvas) { + val xPosition = (width / 2).toFloat() + val yStartPosition = (thumbRadius * 2) + lineWidth + val yEndPosition = height - yStartPosition + canvas.drawLine( + xPosition, yStartPosition, xPosition, yEndPosition, linePaint + ) + } +} \ No newline at end of file diff --git a/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/MyClickableSpan.kt b/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/MyClickableSpan.kt new file mode 100644 index 0000000..81d9176 --- /dev/null +++ b/Demo/app/src/main/java/com/krunal/demo/uicomponents/views/MyClickableSpan.kt @@ -0,0 +1,18 @@ +package com.krunal.demo.uicomponents.views + +import android.text.TextPaint +import android.text.style.ClickableSpan +import android.view.View + +class MyClickableSpan( + private val onTextClick: () -> Unit +) : ClickableSpan() { + override fun onClick(view: View) { + onTextClick() + } + + override fun updateDrawState(ds: TextPaint) { + super.updateDrawState(ds) + ds.isUnderlineText = false + } +} \ No newline at end of file diff --git a/Demo/app/src/main/res/color/chip_card.xml b/Demo/app/src/main/res/color/chip_card.xml new file mode 100644 index 0000000..ed1c356 --- /dev/null +++ b/Demo/app/src/main/res/color/chip_card.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/color/chip_card_text.xml b/Demo/app/src/main/res/color/chip_card_text.xml new file mode 100644 index 0000000..447acf5 --- /dev/null +++ b/Demo/app/src/main/res/color/chip_card_text.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/color/chip_operations_time.xml b/Demo/app/src/main/res/color/chip_operations_time.xml new file mode 100644 index 0000000..cd4dbcd --- /dev/null +++ b/Demo/app/src/main/res/color/chip_operations_time.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/color/stack_exchange_chip_background.xml b/Demo/app/src/main/res/color/stack_exchange_chip_background.xml new file mode 100644 index 0000000..b4b0d3b --- /dev/null +++ b/Demo/app/src/main/res/color/stack_exchange_chip_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/calendar_banner.jpeg b/Demo/app/src/main/res/drawable/calendar_banner.jpeg new file mode 100644 index 0000000..6b784d4 Binary files /dev/null and b/Demo/app/src/main/res/drawable/calendar_banner.jpeg differ diff --git a/Demo/app/src/main/res/drawable/circle_image.xml b/Demo/app/src/main/res/drawable/circle_image.xml new file mode 100644 index 0000000..2051ea6 --- /dev/null +++ b/Demo/app/src/main/res/drawable/circle_image.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/circular_progress.xml b/Demo/app/src/main/res/drawable/circular_progress.xml new file mode 100644 index 0000000..26827c2 --- /dev/null +++ b/Demo/app/src/main/res/drawable/circular_progress.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/dark_forest.jpeg b/Demo/app/src/main/res/drawable/dark_forest.jpeg new file mode 100644 index 0000000..bd25b0d Binary files /dev/null and b/Demo/app/src/main/res/drawable/dark_forest.jpeg differ diff --git a/Demo/app/src/main/res/drawable/gradient_button.xml b/Demo/app/src/main/res/drawable/gradient_button.xml new file mode 100644 index 0000000..1b2e930 --- /dev/null +++ b/Demo/app/src/main/res/drawable/gradient_button.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/Demo/app/src/main/res/drawable/gradient_progress.xml b/Demo/app/src/main/res/drawable/gradient_progress.xml new file mode 100644 index 0000000..5f6dc5f --- /dev/null +++ b/Demo/app/src/main/res/drawable/gradient_progress.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/highlighted_background.xml b/Demo/app/src/main/res/drawable/highlighted_background.xml new file mode 100644 index 0000000..af6d70b --- /dev/null +++ b/Demo/app/src/main/res/drawable/highlighted_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/ic_add.xml b/Demo/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 0000000..70046c4 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_add_filled.xml b/Demo/app/src/main/res/drawable/ic_add_filled.xml new file mode 100644 index 0000000..a14875c --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_add_filled.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_android.xml b/Demo/app/src/main/res/drawable/ic_android.xml new file mode 100644 index 0000000..1168496 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_android.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_avax_logo.xml b/Demo/app/src/main/res/drawable/ic_avax_logo.xml new file mode 100644 index 0000000..c36bcab --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_avax_logo.xml @@ -0,0 +1,9 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_back.xml b/Demo/app/src/main/res/drawable/ic_back.xml new file mode 100644 index 0000000..6c3197a --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_back.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_calendar.xml b/Demo/app/src/main/res/drawable/ic_calendar.xml new file mode 100644 index 0000000..b6caf72 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_calendar.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_call.xml b/Demo/app/src/main/res/drawable/ic_call.xml new file mode 100644 index 0000000..2aba8ad --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_call.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_card.xml b/Demo/app/src/main/res/drawable/ic_card.xml new file mode 100644 index 0000000..838fb42 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_card.xml @@ -0,0 +1,5 @@ + + + + diff --git a/Demo/app/src/main/res/drawable/ic_chat.xml b/Demo/app/src/main/res/drawable/ic_chat.xml new file mode 100644 index 0000000..9e7de07 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_chat.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_check.xml b/Demo/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000..fbc59ec --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,10 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_circle.xml b/Demo/app/src/main/res/drawable/ic_circle.xml new file mode 100644 index 0000000..7c795ea --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_circle.xml @@ -0,0 +1,10 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_cross.xml b/Demo/app/src/main/res/drawable/ic_cross.xml new file mode 100644 index 0000000..70db409 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_cross.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_down_arrow.xml b/Demo/app/src/main/res/drawable/ic_down_arrow.xml new file mode 100644 index 0000000..3dbfedb --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_down_arrow.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_down_arrow_outlined.xml b/Demo/app/src/main/res/drawable/ic_down_arrow_outlined.xml new file mode 100644 index 0000000..1aeaa99 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_down_arrow_outlined.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_email.xml b/Demo/app/src/main/res/drawable/ic_email.xml new file mode 100644 index 0000000..80111c8 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_email.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_exchange.xml b/Demo/app/src/main/res/drawable/ic_exchange.xml new file mode 100644 index 0000000..6f7c7f3 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_exchange.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/Demo/app/src/main/res/drawable/ic_feed.xml b/Demo/app/src/main/res/drawable/ic_feed.xml new file mode 100644 index 0000000..4a4e158 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_feed.xml @@ -0,0 +1,5 @@ + + + + diff --git a/Demo/app/src/main/res/drawable/ic_female.xml b/Demo/app/src/main/res/drawable/ic_female.xml new file mode 100644 index 0000000..ea62387 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_female.xml @@ -0,0 +1,9 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_food.xml b/Demo/app/src/main/res/drawable/ic_food.xml new file mode 100644 index 0000000..45861e1 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_food.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + diff --git a/Demo/app/src/main/res/drawable/ic_gasoline.xml b/Demo/app/src/main/res/drawable/ic_gasoline.xml new file mode 100644 index 0000000..bc05081 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_gasoline.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/Demo/app/src/main/res/drawable/ic_heart_outlined.xml b/Demo/app/src/main/res/drawable/ic_heart_outlined.xml new file mode 100644 index 0000000..58c0403 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_heart_outlined.xml @@ -0,0 +1,4 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_home.xml b/Demo/app/src/main/res/drawable/ic_home.xml new file mode 100644 index 0000000..4c5e854 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_home.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_image.xml b/Demo/app/src/main/res/drawable/ic_image.xml new file mode 100644 index 0000000..d35859d --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_image.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_info.xml b/Demo/app/src/main/res/drawable/ic_info.xml new file mode 100644 index 0000000..e0ecb40 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_info.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_line_shader.xml b/Demo/app/src/main/res/drawable/ic_line_shader.xml new file mode 100644 index 0000000..c775e03 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_line_shader.xml @@ -0,0 +1,4 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_link_logo.xml b/Demo/app/src/main/res/drawable/ic_link_logo.xml new file mode 100644 index 0000000..5eb2e0c --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_link_logo.xml @@ -0,0 +1,4 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_male.xml b/Demo/app/src/main/res/drawable/ic_male.xml new file mode 100644 index 0000000..97af074 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_male.xml @@ -0,0 +1,12 @@ + + + + diff --git a/Demo/app/src/main/res/drawable/ic_market.xml b/Demo/app/src/main/res/drawable/ic_market.xml new file mode 100644 index 0000000..9dd36e5 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_market.xml @@ -0,0 +1,4 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_mastercard.xml b/Demo/app/src/main/res/drawable/ic_mastercard.xml new file mode 100644 index 0000000..3405fd8 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_mastercard.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/Demo/app/src/main/res/drawable/ic_menu.xml b/Demo/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..470db52 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_next.xml b/Demo/app/src/main/res/drawable/ic_next.xml new file mode 100644 index 0000000..4680420 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_next.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_notification.xml b/Demo/app/src/main/res/drawable/ic_notification.xml new file mode 100644 index 0000000..45d15da --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_notification.xml @@ -0,0 +1,4 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_other_gender.xml b/Demo/app/src/main/res/drawable/ic_other_gender.xml new file mode 100644 index 0000000..856139c --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_other_gender.xml @@ -0,0 +1,9 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_paperplane.xml b/Demo/app/src/main/res/drawable/ic_paperplane.xml new file mode 100644 index 0000000..bb0e194 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_paperplane.xml @@ -0,0 +1,5 @@ + + + + diff --git a/Demo/app/src/main/res/drawable/ic_pause.xml b/Demo/app/src/main/res/drawable/ic_pause.xml new file mode 100644 index 0000000..f701d6f --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_pause.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_pause_outlined.xml b/Demo/app/src/main/res/drawable/ic_pause_outlined.xml new file mode 100644 index 0000000..dbf5f42 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_pause_outlined.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_pen.xml b/Demo/app/src/main/res/drawable/ic_pen.xml new file mode 100644 index 0000000..faddfce --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_pen.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_play.xml b/Demo/app/src/main/res/drawable/ic_play.xml new file mode 100644 index 0000000..0870be8 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_play.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_play_outlined.xml b/Demo/app/src/main/res/drawable/ic_play_outlined.xml new file mode 100644 index 0000000..c4f8875 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_play_outlined.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_previous.xml b/Demo/app/src/main/res/drawable/ic_previous.xml new file mode 100644 index 0000000..544bf5b --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_previous.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_profile.xml b/Demo/app/src/main/res/drawable/ic_profile.xml new file mode 100644 index 0000000..ea4bd5c --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_profile.xml @@ -0,0 +1,4 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_remove.xml b/Demo/app/src/main/res/drawable/ic_remove.xml new file mode 100644 index 0000000..128a743 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_remove.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_right_arrow.xml b/Demo/app/src/main/res/drawable/ic_right_arrow.xml new file mode 100644 index 0000000..a749bde --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_right_arrow.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_rose_logo.xml b/Demo/app/src/main/res/drawable/ic_rose_logo.xml new file mode 100644 index 0000000..f418b9e --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_rose_logo.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/Demo/app/src/main/res/drawable/ic_search.xml b/Demo/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 0000000..6031484 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,10 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_splash.xml b/Demo/app/src/main/res/drawable/ic_splash.xml new file mode 100644 index 0000000..ce0d04e --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_splash.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + diff --git a/Demo/app/src/main/res/drawable/ic_swap.xml b/Demo/app/src/main/res/drawable/ic_swap.xml new file mode 100644 index 0000000..d113e11 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_swap.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_timezone.xml b/Demo/app/src/main/res/drawable/ic_timezone.xml new file mode 100644 index 0000000..3476385 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_timezone.xml @@ -0,0 +1,5 @@ + + + + diff --git a/Demo/app/src/main/res/drawable/ic_two_circle.xml b/Demo/app/src/main/res/drawable/ic_two_circle.xml new file mode 100644 index 0000000..87fc77a --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_two_circle.xml @@ -0,0 +1,4 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_up_arrow.xml b/Demo/app/src/main/res/drawable/ic_up_arrow.xml new file mode 100644 index 0000000..ba9e503 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_up_arrow.xml @@ -0,0 +1,5 @@ + + + diff --git a/Demo/app/src/main/res/drawable/ic_wallet.xml b/Demo/app/src/main/res/drawable/ic_wallet.xml new file mode 100644 index 0000000..fc12537 --- /dev/null +++ b/Demo/app/src/main/res/drawable/ic_wallet.xml @@ -0,0 +1,5 @@ + + + + diff --git a/Demo/app/src/main/res/drawable/image_toggle.xml b/Demo/app/src/main/res/drawable/image_toggle.xml new file mode 100644 index 0000000..56adc24 --- /dev/null +++ b/Demo/app/src/main/res/drawable/image_toggle.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/img.png b/Demo/app/src/main/res/drawable/img.png new file mode 100644 index 0000000..bc5121c Binary files /dev/null and b/Demo/app/src/main/res/drawable/img.png differ diff --git a/Demo/app/src/main/res/drawable/profile.jpeg b/Demo/app/src/main/res/drawable/profile.jpeg new file mode 100644 index 0000000..74d27a6 Binary files /dev/null and b/Demo/app/src/main/res/drawable/profile.jpeg differ diff --git a/Demo/app/src/main/res/drawable/progress_vertical.xml b/Demo/app/src/main/res/drawable/progress_vertical.xml new file mode 100644 index 0000000..c4350b1 --- /dev/null +++ b/Demo/app/src/main/res/drawable/progress_vertical.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/progress_vertical_graph.xml b/Demo/app/src/main/res/drawable/progress_vertical_graph.xml new file mode 100644 index 0000000..915dae8 --- /dev/null +++ b/Demo/app/src/main/res/drawable/progress_vertical_graph.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/rounded_bottom_bar.xml b/Demo/app/src/main/res/drawable/rounded_bottom_bar.xml new file mode 100644 index 0000000..b12f214 --- /dev/null +++ b/Demo/app/src/main/res/drawable/rounded_bottom_bar.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/rounded_bottom_sheet.xml b/Demo/app/src/main/res/drawable/rounded_bottom_sheet.xml new file mode 100644 index 0000000..98c2220 --- /dev/null +++ b/Demo/app/src/main/res/drawable/rounded_bottom_sheet.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/rounded_image.xml b/Demo/app/src/main/res/drawable/rounded_image.xml new file mode 100644 index 0000000..b93d8ec --- /dev/null +++ b/Demo/app/src/main/res/drawable/rounded_image.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/rounded_tab_layout.xml b/Demo/app/src/main/res/drawable/rounded_tab_layout.xml new file mode 100644 index 0000000..b576933 --- /dev/null +++ b/Demo/app/src/main/res/drawable/rounded_tab_layout.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/rounded_toast.xml b/Demo/app/src/main/res/drawable/rounded_toast.xml new file mode 100644 index 0000000..db31de8 --- /dev/null +++ b/Demo/app/src/main/res/drawable/rounded_toast.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/rounded_transparent_background.xml b/Demo/app/src/main/res/drawable/rounded_transparent_background.xml new file mode 100644 index 0000000..2526f09 --- /dev/null +++ b/Demo/app/src/main/res/drawable/rounded_transparent_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/running_up_that_hill.png b/Demo/app/src/main/res/drawable/running_up_that_hill.png new file mode 100644 index 0000000..82e0545 Binary files /dev/null and b/Demo/app/src/main/res/drawable/running_up_that_hill.png differ diff --git a/Demo/app/src/main/res/drawable/selected_theme.xml b/Demo/app/src/main/res/drawable/selected_theme.xml new file mode 100644 index 0000000..0c30dbd --- /dev/null +++ b/Demo/app/src/main/res/drawable/selected_theme.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/tab_selected_background.xml b/Demo/app/src/main/res/drawable/tab_selected_background.xml new file mode 100644 index 0000000..a596220 --- /dev/null +++ b/Demo/app/src/main/res/drawable/tab_selected_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/drawable/time_banner.jpeg b/Demo/app/src/main/res/drawable/time_banner.jpeg new file mode 100644 index 0000000..147a3f1 Binary files /dev/null and b/Demo/app/src/main/res/drawable/time_banner.jpeg differ diff --git a/Demo/app/src/main/res/drawable/trade_graph.png b/Demo/app/src/main/res/drawable/trade_graph.png new file mode 100644 index 0000000..034cbc8 Binary files /dev/null and b/Demo/app/src/main/res/drawable/trade_graph.png differ diff --git a/Demo/app/src/main/res/layout/activity_uicomponents.xml b/Demo/app/src/main/res/layout/activity_uicomponents.xml new file mode 100644 index 0000000..5851e1c --- /dev/null +++ b/Demo/app/src/main/res/layout/activity_uicomponents.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/layout/card_chip.xml b/Demo/app/src/main/res/layout/card_chip.xml new file mode 100644 index 0000000..8d95f42 --- /dev/null +++ b/Demo/app/src/main/res/layout/card_chip.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/Demo/app/src/main/res/layout/card_layout.xml b/Demo/app/src/main/res/layout/card_layout.xml new file mode 100644 index 0000000..8448f1c --- /dev/null +++ b/Demo/app/src/main/res/layout/card_layout.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/layout/custom_toast.xml b/Demo/app/src/main/res/layout/custom_toast.xml new file mode 100644 index 0000000..44d0ada --- /dev/null +++ b/Demo/app/src/main/res/layout/custom_toast.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/layout/fragment_app_bar.xml b/Demo/app/src/main/res/layout/fragment_app_bar.xml new file mode 100644 index 0000000..12ac20d --- /dev/null +++ b/Demo/app/src/main/res/layout/fragment_app_bar.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/app/src/main/res/layout/fragment_button.xml b/Demo/app/src/main/res/layout/fragment_button.xml new file mode 100644 index 0000000..d333081 --- /dev/null +++ b/Demo/app/src/main/res/layout/fragment_button.xml @@ -0,0 +1,149 @@ + + + +