>(activity, R.layout.item_simple_list_view, items) {
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val binding = ItemSimpleListViewBinding.inflate(activity.layoutInflater, parent, false)
+ binding.text1.setLeftDrawable(items[position].first)
+ binding.text1.text = items[position].second
+ return binding.root
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/custom_views/ListAdapter.java b/src/main/java/com/nativedevps/support/custom_views/ListAdapter.java
new file mode 100644
index 0000000..39b7078
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/custom_views/ListAdapter.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.nativedevps.support.custom_views;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.AdapterListUpdateCallback;
+import androidx.recyclerview.widget.AsyncDifferConfig;
+import androidx.recyclerview.widget.AsyncListDiffer;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+/**
+ * {@link RecyclerView.Adapter RecyclerView.Adapter} base class for presenting List data in a
+ * {@link RecyclerView}, including computing diffs between Lists on a background thread.
+ *
+ * This class is a convenience wrapper around {@link AsyncListDiffer} that implements Adapter common
+ * default behavior for item access and counting.
+ *
+ * While using a LiveData<List> is an easy way to provide data to the adapter, it isn't required
+ * - you can use {@link #submitList(List)} when new lists are available.
+ *
+ * A complete usage pattern with Room would look like this:
+ *
+ * {@literal @}Dao
+ * interface UserDao {
+ * {@literal @}Query("SELECT * FROM user ORDER BY lastName ASC")
+ * public abstract LiveData<List<User>> usersByLastName();
+ * }
+ *
+ * class MyViewModel extends ViewModel {
+ * public final LiveData<List<User>> usersList;
+ * public MyViewModel(UserDao userDao) {
+ * usersList = userDao.usersByLastName();
+ * }
+ * }
+ *
+ * class MyActivity extends AppCompatActivity {
+ * {@literal @}Override
+ * public void onCreate(Bundle savedState) {
+ * super.onCreate(savedState);
+ * MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
+ * RecyclerView recyclerView = findViewById(R.id.user_list);
+ * UserAdapter<User> adapter = new UserAdapter();
+ * viewModel.usersList.observe(this, list -> adapter.submitList(list));
+ * recyclerView.setAdapter(adapter);
+ * }
+ * }
+ *
+ * class UserAdapter extends ListAdapter<User, UserViewHolder> {
+ * public UserAdapter() {
+ * super(User.DIFF_CALLBACK);
+ * }
+ * {@literal @}Override
+ * public void onBindViewHolder(UserViewHolder holder, int position) {
+ * holder.bindTo(getItem(position));
+ * }
+ * public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK =
+ * new DiffUtil.ItemCallback<User>() {
+ * {@literal @}Override
+ * public boolean areItemsTheSame(
+ * {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
+ * // User properties may have changed if reloaded from the DB, but ID is fixed
+ * return oldUser.getId() == newUser.getId();
+ * }
+ * {@literal @}Override
+ * public boolean areContentsTheSame(
+ * {@literal @}NonNull User oldUser, {@literal @}NonNull User newUser) {
+ * // NOTE: if you use equals, your object must properly override Object#equals()
+ * // Incorrectly returning false here will result in too many animations.
+ * return oldUser.equals(newUser);
+ * }
+ * }
+ * }
+ *
+ * Advanced users that wish for more control over adapter behavior, or to provide a specific base
+ * class should refer to {@link AsyncListDiffer}, which provides custom mapping from diff events
+ * to adapter positions.
+ *
+ * @param Type of the Lists this Adapter will receive.
+ * @param A class that extends ViewHolder that will be used by the adapter.
+ */
+public abstract class ListAdapter
+ extends RecyclerView.Adapter {
+ AsyncListDiffer mDiffer = null;
+ private final AsyncListDiffer.ListListener mListener =
+ new AsyncListDiffer.ListListener() {
+ @Override
+ public void onCurrentListChanged(
+ @NonNull List previousList, @NonNull List currentList) {
+ ListAdapter.this.onCurrentListChanged(previousList, currentList);
+ }
+ };
+
+ protected ListAdapter() {
+ }
+
+ @SuppressWarnings("unused")
+ protected ListAdapter(@NonNull DiffUtil.ItemCallback diffCallback) {
+ mDiffer = new AsyncListDiffer<>(new AdapterListUpdateCallback(this),
+ new AsyncDifferConfig.Builder<>(diffCallback).build());
+ mDiffer.addListListener(mListener);
+ }
+
+ @SuppressWarnings("unused")
+ protected ListAdapter(@NonNull AsyncDifferConfig config) {
+ mDiffer = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), config);
+ mDiffer.addListListener(mListener);
+ }
+
+ protected void init(@NonNull DiffUtil.ItemCallback diffCallback) {
+ mDiffer = new AsyncListDiffer<>(new AdapterListUpdateCallback(this),
+ new AsyncDifferConfig.Builder<>(diffCallback).build());
+ mDiffer.addListListener(mListener);
+ }
+
+ /**
+ * Submits a new list to be diffed, and displayed.
+ *
+ * If a list is already being displayed, a diff will be computed on a background thread, which
+ * will dispatch Adapter.notifyItem events on the main thread.
+ *
+ * @param list The new list to be displayed.
+ */
+ public void submitList(@Nullable List list) {
+ mDiffer.submitList(list);
+ }
+
+ /**
+ * Set the new list to be displayed.
+ *
+ * If a List is already being displayed, a diff will be computed on a background thread, which
+ * will dispatch Adapter.notifyItem events on the main thread.
+ *
+ * The commit callback can be used to know when the List is committed, but note that it
+ * may not be executed. If List B is submitted immediately after List A, and is
+ * committed directly, the callback associated with List A will not be run.
+ *
+ * @param list The new list to be displayed.
+ * @param commitCallback Optional runnable that is executed when the List is committed, if
+ * it is committed.
+ */
+ public void submitList(@Nullable List list, @Nullable final Runnable commitCallback) {
+ mDiffer.submitList(list, commitCallback);
+ }
+
+ protected T getItem(int position) {
+ return mDiffer.getCurrentList().get(position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mDiffer.getCurrentList().size();
+ }
+
+ /**
+ * Get the current List - any diffing to present this list has already been computed and
+ * dispatched via the ListUpdateCallback.
+ *
+ * If a null
List, or no List has been submitted, an empty list will be returned.
+ *
+ * The returned list may not be mutated - mutations to content must be done through
+ * {@link #submitList(List)}.
+ *
+ * @return The list currently being displayed.
+ * @see #onCurrentListChanged(List, List)
+ */
+ @NonNull
+ public List getCurrentList() {
+ return mDiffer.getCurrentList();
+ }
+
+ /**
+ * Called when the current List is updated.
+ *
+ * If a null
List is passed to {@link #submitList(List)}, or no List has been
+ * submitted, the current List is represented as an empty List.
+ *
+ * @param previousList List that was displayed previously.
+ * @param currentList new List being displayed, will be empty if {@code null} was passed to
+ * {@link #submitList(List)}.
+ * @see #getCurrentList()
+ */
+ public void onCurrentListChanged(@NonNull List previousList, @NonNull List currentList) {
+ }
+}
diff --git a/src/main/java/com/nativedevps/support/custom_views/OneTimePasswordEditText.java b/src/main/java/com/nativedevps/support/custom_views/OneTimePasswordEditText.java
new file mode 100644
index 0000000..cdabc77
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/custom_views/OneTimePasswordEditText.java
@@ -0,0 +1,103 @@
+package com.nativedevps.support.custom_views;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.text.Editable;
+import android.util.AttributeSet;
+import android.view.ActionMode;
+import android.view.View;
+import androidx.appcompat.widget.AppCompatEditText;
+
+import nativedevps.support.R;
+
+
+public class OneTimePasswordEditText extends AppCompatEditText {
+ private float mSpace = 24; //24 dp by default, space between the lines
+ private float mNumChars = 6;
+ private float mLineSpacing = 8; //8dp by default, height of the text from our lines
+ private int mMaxLength = 4;
+ private float mLineStroke = 2;
+ private Paint mLinesPaint;
+ private OnClickListener mClickListener;
+
+ public OneTimePasswordEditText(Context context) {
+ super(context);
+ }
+
+ public OneTimePasswordEditText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs);
+ }
+
+ public OneTimePasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
+
+ private void init(Context context, AttributeSet attrs) {
+ float multi = context.getResources().getDisplayMetrics().density;
+ mLineStroke = multi * mLineStroke;
+ mLinesPaint = new Paint(getPaint());
+ mLinesPaint.setStrokeWidth(mLineStroke);
+ mLinesPaint.setColor(getResources().getColor(R.color.trans_gray));
+ setBackgroundResource(0);
+ mSpace = multi * mSpace; //convert to pixels for our density
+ mLineSpacing = multi * mLineSpacing; //convert to pixels for our density
+ mNumChars = mMaxLength;
+
+ super.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // When tapped, move cursor to end of text.
+ setSelection(getText().length());
+ if (mClickListener != null) {
+ mClickListener.onClick(v);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener l) {
+ mClickListener = l;
+ }
+
+ @Override
+ public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
+ throw new RuntimeException("setCustomSelectionActionModeCallback() not supported.");
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int availableWidth = getWidth() - getPaddingRight() - getPaddingLeft();
+ float mCharSize;
+ if (mSpace < 0) {
+ mCharSize = (availableWidth / (mNumChars * 2 - 1));
+ } else {
+ mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars;
+ }
+
+ int startX = getPaddingLeft();
+ int bottom = getHeight() - getPaddingBottom();
+
+ //Text Width
+ Editable text = getText();
+ int textLength = text.length();
+ float[] textWidths = new float[textLength];
+ getPaint().getTextWidths(getText(), 0, textLength, textWidths);
+
+ for (int i = 0; i < mNumChars; i++) {
+ canvas.drawLine(startX, bottom, startX + mCharSize, bottom, mLinesPaint);
+ if (getText().length() > i) {
+ float middle = startX + mCharSize / 2;
+ canvas.drawText(text, i, i + 1, middle - textWidths[0] / 2, bottom - mLineSpacing, getPaint());
+ }
+ if (mSpace < 0) {
+ startX += mCharSize * 2;
+ } else {
+ startX += mCharSize + mSpace;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/custom_views/ProgressDialog.kt b/src/main/java/com/nativedevps/support/custom_views/ProgressDialog.kt
new file mode 100644
index 0000000..af4a17e
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/custom_views/ProgressDialog.kt
@@ -0,0 +1,53 @@
+package com.nativedevps.support.custom_views
+
+import android.content.Context
+import android.os.Build
+import com.google.android.material.progressindicator.CircularProgressIndicator
+import com.nativedevps.support.base_class.dialog.BaseMaterialDialog
+import nativedevps.support.databinding.DProgressBarBinding
+
+
+class ProgressDialog(context: Context) :
+ BaseMaterialDialog(context, DProgressBarBinding::inflate) {
+
+ override fun onCreate(binding: DProgressBarBinding) {
+ setMessage("Loading..")
+ progressBar.setOnClickListener {
+ setProgress(progressBar.progress + 10)
+ }
+ }
+
+ fun setIndeterminate(boolean: Boolean): ProgressDialog {
+ progressBar.isIndeterminate = boolean
+ return this
+ }
+
+ fun setMessage(string: String): ProgressDialog {
+ binding.messageAppCompatTextView.text = string
+ return this
+ }
+
+ fun setProgress(int: Int): ProgressDialog {
+ if (int == -1) {
+ return this
+ }
+ if (progressBar.isIndeterminate) {
+ progressBar.isIndeterminate = false
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ progressBar.setProgress(int, true)
+ } else {
+ progressBar.progress = int
+ }
+ return this
+ }
+
+ fun build(): ProgressDialog {
+ if (!isShowing()) {
+ show()
+ }
+ return this
+ }
+
+ private val progressBar: CircularProgressIndicator get() = binding.progressCircularProgressIndicator
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/inline/orElse.kt b/src/main/java/com/nativedevps/support/inline/orElse.kt
new file mode 100644
index 0000000..44ece4e
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/inline/orElse.kt
@@ -0,0 +1,6 @@
+package com.nativedevps.support.inline
+
+//?.let{}.orElse{}
+inline fun R?.orElse(block: () -> R): R {
+ return this ?: block()
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/inline/viewModels.kt b/src/main/java/com/nativedevps/support/inline/viewModels.kt
new file mode 100644
index 0000000..457f356
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/inline/viewModels.kt
@@ -0,0 +1,18 @@
+package com.nativedevps.support.inline
+
+import androidx.activity.ComponentActivity
+import androidx.annotation.MainThread
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelLazy
+import androidx.lifecycle.ViewModelProvider.Factory
+
+@MainThread
+inline fun ComponentActivity.viewModels(
+ noinline factoryProducer: (() -> Factory)? = null,
+): Lazy {
+ val factoryPromise = factoryProducer ?: {
+ defaultViewModelProviderFactory
+ }
+
+ return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/date_time_utility/DateTimeConversion.kt b/src/main/java/com/nativedevps/support/utility/date_time_utility/DateTimeConversion.kt
new file mode 100644
index 0000000..81cbf9d
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/date_time_utility/DateTimeConversion.kt
@@ -0,0 +1,4 @@
+package com.nativedevps.support.utility.date_time_utility
+
+object DateTimeConversion {
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/date_time_utility/DateUtility.kt b/src/main/java/com/nativedevps/support/utility/date_time_utility/DateUtility.kt
new file mode 100644
index 0000000..1a3db3e
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/date_time_utility/DateUtility.kt
@@ -0,0 +1,4 @@
+package com.nativedevps.support.utility.date_time_utility
+
+object DateUtility {
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/date_time_utility/MillisecondUtility.kt b/src/main/java/com/nativedevps/support/utility/date_time_utility/MillisecondUtility.kt
new file mode 100644
index 0000000..3319a83
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/date_time_utility/MillisecondUtility.kt
@@ -0,0 +1,5 @@
+package com.nativedevps.support.utility.date_time_utility
+
+object MillisecondUtility {
+ val now: Long get() = System.currentTimeMillis()
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/date_time_utility/TimeUtility.kt b/src/main/java/com/nativedevps/support/utility/date_time_utility/TimeUtility.kt
new file mode 100644
index 0000000..3030677
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/date_time_utility/TimeUtility.kt
@@ -0,0 +1,4 @@
+package com.nativedevps.support.utility.date_time_utility
+
+object TimeUtility {
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/device/AppSignatureHelper.kt b/src/main/java/com/nativedevps/support/utility/device/AppSignatureHelper.kt
new file mode 100644
index 0000000..ebf574b
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/device/AppSignatureHelper.kt
@@ -0,0 +1,79 @@
+package com.nativedevps.support.utility.device
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.pm.PackageManager
+import android.util.Base64
+import android.util.Log
+import java.nio.charset.StandardCharsets
+import java.security.MessageDigest
+import java.security.NoSuchAlgorithmException
+import java.util.ArrayList
+import java.util.Arrays
+
+/**
+ * Created on : May 21, 2019
+ * Author : AndroidWave
+ */
+class AppSignatureHelper(context: Context) : ContextWrapper(context) {
+
+ /**
+ * Get all the app signatures for the current package
+ */
+ // Get all package signatures for the current package
+ // For each signature create a compatible hash
+ val appSignatures: ArrayList
+ get() {
+ val appCodes = ArrayList()
+
+ try {
+ val packageName = packageName
+ val packageManager = packageManager
+ val signatures = packageManager.getPackageInfo(
+ packageName,
+ PackageManager.GET_SIGNATURES
+ ).signatures
+ for (signature in signatures) {
+ val hash = hash(packageName, signature.toCharsString())
+ if (hash != null) {
+ appCodes.add(String.format("%s", hash))
+ }
+ }
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(TAG, "Unable to find package to obtain hash.", e)
+ }
+
+ return appCodes
+ }
+
+ companion object {
+
+ private val TAG = "AppSignatureHelper"
+ private val HASH_TYPE = "SHA-256"
+ val NUM_HASHED_BYTES = 9
+ val NUM_BASE64_CHAR = 11
+
+ private fun hash(packageName: String, signature: String): String? {
+ val appInfo = "$packageName $signature"
+ try {
+ val messageDigest = MessageDigest.getInstance(HASH_TYPE)
+ messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8))
+ var hashSignature = messageDigest.digest()
+
+ // truncated into NUM_HASHED_BYTES
+ hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES)
+ // encode into Base64
+ var base64Hash =
+ Base64.encodeToString(hashSignature, Base64.NO_PADDING or Base64.NO_WRAP)
+ base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR)
+
+ Log.d(TAG, String.format("pkg: %s -- hash: %s", packageName, base64Hash))
+ return base64Hash
+ } catch (e: NoSuchAlgorithmException) {
+ Log.e(TAG, "hash:NoSuchAlgorithm", e)
+ }
+
+ return null
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/device/audio/DeviceAudio.kt b/src/main/java/com/nativedevps/support/utility/device/audio/DeviceAudio.kt
new file mode 100644
index 0000000..9644aaa
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/device/audio/DeviceAudio.kt
@@ -0,0 +1,13 @@
+package com.nativedevps.support.utility.device.audio
+
+import android.content.Context
+import android.media.AudioManager
+
+object DeviceAudio {
+ fun Context.getCurrentVolume(): Int {
+ val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
+ val volumeLevel: Int = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
+ val maxVolumeLevel: Int = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
+ return (volumeLevel.toFloat() / maxVolumeLevel * 100).toInt()
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/device/mime/MimeWildCard.kt b/src/main/java/com/nativedevps/support/utility/device/mime/MimeWildCard.kt
new file mode 100644
index 0000000..79065a4
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/device/mime/MimeWildCard.kt
@@ -0,0 +1,7 @@
+package com.nativedevps.support.utility.device.mime
+
+object MimeWildCard {
+ val MIME_IMAGE_WILD_CARD = "image/*"
+ val MIME_VIDEO_WILD_CARD = "video/*"
+ val MIME_APPLICATION_WILD_CARD = "application/*"
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/device/permission/EasyPermissions.kt b/src/main/java/com/nativedevps/support/utility/device/permission/EasyPermissions.kt
new file mode 100644
index 0000000..bc02fe5
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/device/permission/EasyPermissions.kt
@@ -0,0 +1,412 @@
+package com.nativedevps.support.utility.device.permission
+
+import android.Manifest
+import android.R
+import android.annotation.TargetApi
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.provider.Settings
+import android.text.TextUtils
+import android.util.Log
+import androidx.annotation.StringRes
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import java.util.*
+
+object EasyPermissions {
+
+ private val TAG = "EasyPermissions"
+ internal var timeWhenRequestingStart: Long = 0
+ internal lateinit var `object`: Any
+ //private var finalPermissionDialog: MConfirmationDialog? = null
+ private var callbacks: PermissionCallbacks? = null
+ private var permissionGroups: HashMap>? = null
+
+ /**
+ * Check if the calling context has a set of permissions.
+ *
+ * @param context the calling context.
+ * @param perms one ore more permissions, such as `android.Manifest.permission.CAMERA`.
+ * @return true if all permissions are already granted, false if at least one permission
+ * is not yet granted.
+ */
+ fun hasPermissions(context: Context?, vararg perms: String): Boolean {
+ // Always return true for SDK < M, let the system deal with the permissions
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ Log.w(TAG, "hasPermissions: API version < M, returning true by default")
+ return true
+ }
+
+ for (perm in perms) {
+ val hasPerm = ContextCompat.checkSelfPermission(context!!, perm) == PackageManager.PERMISSION_GRANTED
+ if (!hasPerm) {
+ return false
+ }
+ }
+
+ return true
+ }
+
+ /**
+ * Request a set of permissions, showing rationale if the system requests it.
+ *
+ * @param object Activity or Fragment requesting permissions. Should implement
+ * [ActivityCompat.OnRequestPermissionsResultCallback]
+ * or
+ * @param rationale a message explaining why the application needs this set of permissions, will
+ * be displayed if the user rejects the request the first time.
+ * @param requestCode request code to track this request, must be < 256.
+ * @param perms a set of permissions to be requested.
+ */
+ fun requestPermissions(
+ `object`: Any, rationale: String,
+ requestCode: Int, callback: PermissionCallbacks, vararg perms: String
+ ) {
+ requestPermissions(
+ `object`, rationale,
+ R.string.ok,
+ R.string.cancel,
+ requestCode, callback, *perms
+ )
+ }
+
+ /**
+ * Request a set of permissions, showing rationale if the system requests it.
+ *
+ * @param object Activity or Fragment requesting permissions. Should implement
+ * [ActivityCompat.OnRequestPermissionsResultCallback]
+ * or
+ * be displayed if the user rejects the request the first time.
+ * @param requestCode request code to track this request, must be < 256.
+ * @param perms a set of permissions to be requested.
+ */
+ fun requestPermissions(
+ `object`: Any,
+ requestCode: Int, callback: PermissionCallbacks, vararg perms: String
+ ) {
+ requestPermissions(
+ `object`, "",
+ R.string.ok,
+ R.string.cancel,
+ requestCode, callback, *perms
+ )
+ }
+
+ /**
+ * Request a set of permissions, showing rationale if the system requests it.
+ *
+ * @param obj Activity or Fragment requesting permissions. Should implement
+ * [ActivityCompat.OnRequestPermissionsResultCallback]
+ * or
+ * @param rationale a message explaining why the application needs this set of permissions, will
+ * be displayed if the user rejects the request the first time.
+ * @param positiveButton custom text for positive button
+ * @param negativeButton custom text for negative button
+ * @param requestCode request code to track this request, must be < 256.
+ * @param permission a set of permissions or permission.group to be requested.
+ */
+ fun requestPermissions(
+ obj: Any, rationale: String,
+ @StringRes positiveButton: Int,
+ @StringRes negativeButton: Int,
+ requestCode: Int, callback: PermissionCallbacks, vararg permission: String
+ ) {
+
+ callbacks = callback
+ `object` = obj
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ // only for lower of M
+ // PermissionCallbacks callbacks = (PermissionCallbacks) object;
+ callbacks!!.onPermissionsGranted(requestCode, ArrayList(Arrays.asList(*permission)))
+ return
+ }
+
+
+ checkCallingObjectSuitability(`object`)
+ // final PermissionCallbacks callbacks = (PermissionCallbacks) object;
+ val perms = getActualPermissions(
+ `object`,
+ permission
+ )
+
+ if (perms.size <= 0) {
+ callbacks!!.onPermissionsGranted(requestCode, ArrayList(Arrays.asList(*permission)))
+ return
+ }
+
+ var shouldShowRationale = false
+ for (perm in perms) {
+ shouldShowRationale = shouldShowRationale || shouldShowRequestPermissionRationale(
+ `object`, perm)
+ }
+
+ if (shouldShowRationale) {
+ if (!TextUtils.isEmpty(rationale)) {
+ Log.i(TAG, "shouldShowRationale: ")
+
+// val builder = MConfirmationDialog.Builder(getActivity(`object`)!!)
+// .setMessage(rationale)
+// .setTitle("Permission necessary")
+// .setPositiveButton(positiveButton)
+// .setNegativeButton(negativeButton)
+// .setOnNegativeClickListener(DialogInterface.OnClickListener { dialog, which ->
+// callbacks!!.onPermissionsDenied(requestCode, Arrays.asList(*perms))
+// finalPermissionDialog!!.dismiss()
+// }).setOnPositiveClickListener(DialogInterface.OnClickListener { dialog, which ->
+// executePermissionsRequest(`object`, perms, requestCode)
+// finalPermissionDialog!!.dismiss()
+// })
+// finalPermissionDialog = MConfirmationDialog(getActivity(`object`), builder)
+// finalPermissionDialog!!.show()
+ } else {
+ executePermissionsRequest(`object`, perms, requestCode)
+ }
+ } else {
+ for (perm in perms) {
+ shouldShowRationale = shouldShowRationale || shouldShowRequestPermissionRationale(
+ `object`, perm)
+ }
+ if (shouldShowRationale) {
+ Log.d(TAG, "requestPermissions: show dialog")
+
+ } else {
+ timeWhenRequestingStart = System.currentTimeMillis()
+ executePermissionsRequest(`object`, perms, requestCode)
+ }
+
+ }
+ }
+
+
+ private fun getActualPermissions(`object`: Any, permission: Array): Array {
+ initPermissionGroups()
+ val permissionList = ArrayList()
+ for (indiPerm in permission) {
+ if (permissionGroups!!.containsKey(indiPerm)) {
+ val arr = permissionGroups!![indiPerm]
+ for (s in arr!!) {
+ if (!hasPermissions(getActivity(`object`), s)) {
+ permissionList.add(s)
+ }
+ }
+ } else {
+ if (!hasPermissions(getActivity(`object`), indiPerm)) {
+ permissionList.add(indiPerm)
+ }
+ }
+ }
+ val set = LinkedHashSet(permissionList)
+
+ return set.toTypedArray()
+ }
+
+ private fun initPermissionGroups() {
+ if (permissionGroups == null) {
+ permissionGroups = HashMap()
+ permissionGroups!![Manifest.permission_group.CALENDAR] =
+ arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR)
+ permissionGroups!![Manifest.permission_group.CAMERA] = arrayOf(Manifest.permission.CAMERA)
+ permissionGroups!![Manifest.permission_group.CONTACTS] =
+ arrayOf(
+ Manifest.permission.READ_CONTACTS,
+ Manifest.permission.WRITE_CONTACTS,
+ Manifest.permission.GET_ACCOUNTS
+ )
+ permissionGroups!![Manifest.permission_group.LOCATION] =
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
+ permissionGroups!![Manifest.permission_group.MICROPHONE] = arrayOf(Manifest.permission.RECORD_AUDIO)
+ permissionGroups!![Manifest.permission_group.PHONE] = arrayOf(
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.CALL_PHONE,
+ Manifest.permission.READ_CALL_LOG,
+ Manifest.permission.WRITE_CALL_LOG,
+ Manifest.permission.ADD_VOICEMAIL,
+ Manifest.permission.USE_SIP,
+ Manifest.permission.PROCESS_OUTGOING_CALLS
+ )
+ permissionGroups!![Manifest.permission_group.SENSORS] = arrayOf(Manifest.permission.BODY_SENSORS)
+ permissionGroups!![Manifest.permission_group.SMS] = arrayOf(
+ Manifest.permission.SEND_SMS,
+ Manifest.permission.RECEIVE_SMS,
+ Manifest.permission.READ_SMS,
+ Manifest.permission.RECEIVE_WAP_PUSH,
+ Manifest.permission.RECEIVE_MMS
+ )
+ permissionGroups!![Manifest.permission_group.STORAGE] =
+ arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ }
+ }
+
+ /**
+ * Handle the result of a permission request, should be called from the calling Activity's
+ * [ActivityCompat.OnRequestPermissionsResultCallback.onRequestPermissionsResult]
+ * method.
+ *
+ *
+ * If any permissions were granted or denied, the Activity will receive the appropriate
+ * callbacks through [PermissionCallbacks] and methods annotated with
+ *
+ * @param requestCode requestCode argument to permission result callback.
+ * @param permissions permissions argument to permission result callback.
+ * @param grantResults grantResults argument to permission result callback.
+ * @throws IllegalArgumentException if the calling Activity does not implement
+ * [PermissionCallbacks].
+ */
+ fun onRequestPermissionsResult(
+ requestCode: Int, permissions: Array,
+ grantResults: IntArray
+ ) {
+ var isPermenantlyDisabled = false
+ // checkCallingObjectSuitability(object);
+ // PermissionCallbacks callbacks = (PermissionCallbacks) object;
+
+ // Make a collection of granted and denied permissions from the request.
+ val granted = ArrayList()
+ val denied = ArrayList()
+ for (i in permissions.indices) {
+ val perm = permissions[i]
+ if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
+ granted.add(perm)
+ } else {
+ /**if deny then it will true and on never as me again it will return false
+ */
+ if(EasyPermissions::`object`.isInitialized) {
+ val showRationale = shouldShowRequestPermissionRationale(`object`, perm)
+ if (showRationale) {
+ isPermenantlyDisabled = false //deny
+ // timeWhenRequestingStart = System.currentTimeMillis() - 2;
+ } else {
+ isPermenantlyDisabled = true //never ask me again
+ }
+ denied.add(perm)
+ }
+ }
+ }
+
+ // Report granted permissions, if any.
+ if (!granted.isEmpty() && denied.isEmpty()) {
+ // Notify callbacks
+ callbacks!!.onPermissionsGranted(requestCode, granted)
+ } else if (granted.isEmpty() && !denied.isEmpty() && isPermenantlyDisabled) {
+ val diff = System.currentTimeMillis() - timeWhenRequestingStart
+ // if (diff < 350) {
+ //means it is permenantly disabled
+ callbacks!!.onPermissionsPermanentlyDeclined(requestCode, denied)
+ // }
+ Log.i("TAG", diff.toString() + "")
+ }// Report denied permissions, if any.
+ /*if (!denied.isEmpty()) {
+ callbacks.onPermissionsDenied(requestCode, denied);
+ }*///if 100% fail then check for whether timing
+
+ // Report denied permissions, if any.
+ if (!denied.isEmpty() && !isPermenantlyDisabled) {
+ callbacks!!.onPermissionsDenied(requestCode, denied)
+ }
+
+ /*// If 100% successful, call annotated methods
+ if (!granted.isEmpty() && denied.isEmpty()) {
+ runAnnotatedMethods(object, requestCode);
+ }*/
+ }
+
+ @TargetApi(23)
+ private fun shouldShowRequestPermissionRationale(`object`: Any, perm: String): Boolean {
+ return if (`object` is Activity) {
+ ActivityCompat.shouldShowRequestPermissionRationale(`object`, perm)
+ } else (`object` as? Fragment)?.shouldShowRequestPermissionRationale(perm)
+ ?: ((`object` as? android.app.Fragment)?.shouldShowRequestPermissionRationale(perm) ?: false)
+ }
+
+ @TargetApi(23)
+ private fun executePermissionsRequest(`object`: Any, perms: Array, requestCode: Int) {
+ checkCallingObjectSuitability(`object`)
+
+ if (`object` is Activity) {
+ ActivityCompat.requestPermissions(`object`, perms, requestCode)
+ } else if (`object` is Fragment) {
+ `object`.requestPermissions(perms, requestCode)
+ } else if (`object` is android.app.Fragment) {
+ `object`.requestPermissions(perms, requestCode)
+ }
+ }
+
+ @TargetApi(11)
+ private fun getActivity(`object`: Any): Activity? {
+ return `object` as? Activity ?: if (`object` is Fragment) {
+ `object`.activity
+ } else if (`object` is android.app.Fragment) {
+ `object`.activity
+ } else {
+ null
+ }
+ }
+
+ private fun checkCallingObjectSuitability(`object`: Any) {
+ // Make sure Object is an Activity or Fragment
+ val isActivity = `object` is Activity
+ val isSupportFragment = `object` is Fragment
+ val isAppFragment = `object` is android.app.Fragment
+ val isMinSdkM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+
+ if (!(isSupportFragment || isActivity || isAppFragment && isMinSdkM)) {
+ if (isAppFragment) {
+ throw IllegalArgumentException(
+ "Target SDK needs to be greater than 23 if caller is android.app.Fragment"
+ )
+ } else {
+ throw IllegalArgumentException("Caller must be an Activity or a Fragment.")
+ }
+ }
+
+ /*// Make sure Object implements callbacks
+ if (!(object instanceof PermissionCallbacks)) {
+ throw new IllegalArgumentException("Caller must implement PermissionCallbacks.");
+ }*/
+ }
+
+ fun startSetting() {
+ val intent = Intent()
+ intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+ val uri = Uri.fromParts("package", getActivity(`object`)!!.packageName, null)
+ intent.data = uri
+ getActivity(`object`)!!.startActivity(intent)
+ }
+
+ interface PermissionCallbacks {
+
+ fun onPermissionsGranted(requestCode: Int, perms: List)
+
+ fun onPermissionsDenied(requestCode: Int, perms: List)
+
+ fun onPermissionsPermanentlyDeclined(requestCode: Int, perms: List)
+ }
+
+ /*private fun showSamplePermission() {
+ EasyPermissions.requestPermissions(this, "Rational message", 102, object : EasyPermissions.PermissionCallbacks {
+ override fun onPermissionsGranted(requestCode: Int, perms: List) {
+ Log.w("Permission:", "GRANTED");
+ }
+
+ override fun onPermissionsDenied(requestCode: Int, perms: List) {
+ Log.w("Permission:", "Denied");
+ }
+
+ override fun onPermissionsPermanentlyDeclined(requestCode: Int, perms: List) {
+ Log.w("Permission:", "Declined");
+ }
+
+ }, Manifest.permission.READ_EXTERNAL_STORAGE)
+ }
+
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ }*/
+
+}
diff --git a/src/main/java/com/nativedevps/support/utility/device/permission/Utility.kt b/src/main/java/com/nativedevps/support/utility/device/permission/Utility.kt
new file mode 100644
index 0000000..d91bfb2
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/device/permission/Utility.kt
@@ -0,0 +1,33 @@
+package com.nativedevps.support.utility.device.permission
+
+import android.Manifest.permission.READ_EXTERNAL_STORAGE
+import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+import android.app.Activity
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Build.VERSION.SDK_INT
+import android.os.Environment
+import androidx.core.content.ContextCompat
+
+
+object Utility {
+ fun Activity.checkReadPermission(): Boolean {
+ return if (SDK_INT >= Build.VERSION_CODES.R) {
+ Environment.isExternalStorageManager()
+ } else {
+ val result =
+ ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE)
+ result == PackageManager.PERMISSION_GRANTED
+ }
+ }
+
+ fun Activity.checkWritePermission(): Boolean {
+ return if (SDK_INT >= Build.VERSION_CODES.R) {
+ Environment.isExternalStorageManager()
+ } else {
+ val result1 =
+ ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE)
+ result1 == PackageManager.PERMISSION_GRANTED
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/device/storage_access_framework/UriHelper.kt b/src/main/java/com/nativedevps/support/utility/device/storage_access_framework/UriHelper.kt
new file mode 100644
index 0000000..2411c95
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/device/storage_access_framework/UriHelper.kt
@@ -0,0 +1,41 @@
+package com.nativedevps.support.utility.device.storage_access_framework
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Intent
+import android.database.Cursor
+import android.net.Uri
+import android.os.Build
+import android.provider.OpenableColumns
+import androidx.annotation.RequiresApi
+
+
+object UriHelper {
+ @RequiresApi(Build.VERSION_CODES.KITKAT)
+ fun Context.getPersistablePermission(uri: Uri): Uri {
+ contentResolver.takePersistableUriPermission(uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ return uri
+ }
+
+ @SuppressLint("Range")
+ fun Context.getFileName(uri: Uri): String? {
+ var result: String? = null
+ if (uri.scheme == "content") {
+ val cursor: Cursor = contentResolver.query(uri, null, null, null, null)!!
+ cursor.use { cursor ->
+ if (cursor.moveToFirst()) {
+ result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
+ }
+ }
+ }
+ if (result == null) {
+ result = uri.path
+ val cut = result!!.lastIndexOf('/')
+ if (cut != -1) {
+ result = result?.substring(cut + 1)
+ }
+ }
+ return result
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/device/storage_access_framework/Utility.kt b/src/main/java/com/nativedevps/support/utility/device/storage_access_framework/Utility.kt
new file mode 100644
index 0000000..0c1a2db
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/device/storage_access_framework/Utility.kt
@@ -0,0 +1,22 @@
+package com.nativedevps.support.utility.device.storage_access_framework
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Build
+import com.nativedevps.support.utility.device.mime.MimeWildCard.MIME_IMAGE_WILD_CARD
+
+object Utility {
+ fun Activity.showGalleryPicker(mime: String = MIME_IMAGE_WILD_CARD, reqCode: Int) {
+ if (Build.VERSION.SDK_INT >= 19) {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
+ intent.type = mime
+ intent.addCategory(Intent.CATEGORY_OPENABLE)
+ startActivityForResult(intent, reqCode)
+ } else {
+ val intent = Intent(Intent.ACTION_GET_CONTENT)
+ intent.type = mime
+ intent.addCategory(Intent.CATEGORY_OPENABLE)
+ startActivityForResult(intent, reqCode)
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/image/bitmap/Parceling.kt b/src/main/java/com/nativedevps/support/utility/image/bitmap/Parceling.kt
new file mode 100644
index 0000000..35f0b52
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/image/bitmap/Parceling.kt
@@ -0,0 +1,23 @@
+package com.nativedevps.support.utility.image.bitmap
+
+import android.graphics.Bitmap
+import android.util.Base64
+import java.io.ByteArrayOutputStream
+
+
+object Parceling {
+ fun Bitmap.toBase64(): String? {
+ var byteArrayOutputStream: ByteArrayOutputStream? = null
+ try {
+ byteArrayOutputStream = ByteArrayOutputStream()
+ compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)
+ val bytes: ByteArray = byteArrayOutputStream.toByteArray()
+ return Base64.encodeToString(bytes, Base64.DEFAULT)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ byteArrayOutputStream?.close()
+ }
+ return null
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/image/bitmap/Utility.kt b/src/main/java/com/nativedevps/support/utility/image/bitmap/Utility.kt
new file mode 100644
index 0000000..c58dd64
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/image/bitmap/Utility.kt
@@ -0,0 +1,21 @@
+package com.nativedevps.support.utility.image.bitmap
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.net.Uri
+import java.io.InputStream
+
+
+object Utility {
+ @Throws(OutOfMemoryError::class)
+ fun Context.getBitmap(uri: Uri): Bitmap? {
+ var inputStream: InputStream? = null
+ try {
+ inputStream = contentResolver.openInputStream(uri);
+ return BitmapFactory.decodeStream(inputStream)
+ } finally {
+ inputStream?.close()
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/language/ContextWrapper.java b/src/main/java/com/nativedevps/support/utility/language/ContextWrapper.java
new file mode 100644
index 0000000..13bf14b
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/language/ContextWrapper.java
@@ -0,0 +1,37 @@
+package com.nativedevps.support.utility.language;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.LocaleList;
+
+import java.util.Locale;
+
+public class ContextWrapper extends android.content.ContextWrapper {
+
+ public ContextWrapper(Context base) {
+ super(base);
+ }
+
+ public static ContextWrapper wrap(Context context, Locale newLocale) {
+ Resources res = context.getResources();
+ Configuration configuration = res.getConfiguration();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ configuration.setLocale(newLocale);
+
+ LocaleList localeList = new LocaleList(newLocale);
+ LocaleList.setDefault(localeList);
+ configuration.setLocales(localeList);
+
+ context = context.createConfigurationContext(configuration);
+
+ } else {
+ configuration.locale = newLocale;
+ res.updateConfiguration(configuration, res.getDisplayMetrics());
+ }
+
+ return new ContextWrapper(context);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/language/Utility.kt b/src/main/java/com/nativedevps/support/utility/language/Utility.kt
new file mode 100644
index 0000000..1d86c20
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/language/Utility.kt
@@ -0,0 +1,16 @@
+package com.nativedevps.support.utility.language
+
+import android.content.res.Resources
+import android.os.Build
+import java.util.*
+
+object Utility {
+
+ fun getDeviceLocale(): Locale? {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ Resources.getSystem().configuration.locales.get(0)
+ } else {
+ Resources.getSystem().configuration.locale
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/room/DateConverter.kt b/src/main/java/com/nativedevps/support/utility/room/DateConverter.kt
new file mode 100644
index 0000000..123f32f
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/room/DateConverter.kt
@@ -0,0 +1,17 @@
+package com.nativedevps.support.utility.room
+
+import androidx.room.TypeConverter
+import org.joda.time.DateTime
+
+class DateConverter {
+
+ @TypeConverter
+ fun toDate(timestamp: Long?): DateTime? {
+ return if (timestamp == null) null else DateTime(timestamp)
+ }
+
+ @TypeConverter
+ fun toTimestamp(date: DateTime?): Long? {
+ return date?.millis
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/shared_preference/SharedPreferences.java b/src/main/java/com/nativedevps/support/utility/shared_preference/SharedPreferences.java
new file mode 100644
index 0000000..2084404
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/shared_preference/SharedPreferences.java
@@ -0,0 +1,513 @@
+package com.nativedevps.support.utility.shared_preference;
+
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences.Editor;
+import android.os.Build;
+import android.text.TextUtils;
+
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+@SuppressWarnings("unused")
+public final class SharedPreferences {
+ private static final String DEFAULT_SUFFIX = "_preferences";
+ private static final String LENGTH = "#LENGTH";
+ private static android.content.SharedPreferences mPrefs;
+
+ /**
+ * Initialize the Prefs helper class to keep a reference to the SharedPreference for this
+ * application the SharedPreference will use the package name of the application as the Key.
+ * This method is deprecated please us the new builder.
+ *
+ * @param context the Application context.
+ */
+ @Deprecated
+ public static void initPrefs(Context context) {
+ new Builder().setContext(context).build();
+ }
+
+ private static void initPrefs(Context context, String prefsName, int mode) {
+ mPrefs = context.getSharedPreferences(prefsName, mode);
+ }
+
+ /**
+ * Returns the underlying SharedPreference instance
+ *
+ * @return an instance of the SharedPreference
+ * @throws RuntimeException if SharedPreference instance has not been instantiated yet.
+ */
+ public static android.content.SharedPreferences getPreferences() {
+ if (mPrefs != null) {
+ return mPrefs;
+ }
+ throw new RuntimeException(
+ "Prefs class not correctly instantiated. Please call Builder.setContext().build() in the Application class onCreate.");
+ }
+
+ /**
+ * @return Returns a map containing a list of pairs key/value representing
+ * the preferences.
+ * @see android.content.SharedPreferences#getAll()
+ */
+ public static Map getAll() {
+ return getPreferences().getAll();
+ }
+
+ /**
+ * Retrieves a stored int value.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @return Returns the preference value if it exists, or defValue.
+ * @throws ClassCastException if there is a preference with this name that is not
+ * an int.
+ * @see android.content.SharedPreferences#getInt(String, int)
+ */
+ public static int getInt(final String key, final int defValue) {
+ return getPreferences().getInt(key, defValue);
+ }
+
+ /**
+ * Retrieves a stored boolean value.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @return Returns the preference value if it exists, or defValue.
+ * @throws ClassCastException if there is a preference with this name that is not a boolean.
+ * @see android.content.SharedPreferences#getBoolean(String, boolean)
+ */
+ public static boolean getBoolean(final String key, final boolean defValue) {
+ return getPreferences().getBoolean(key, defValue);
+ }
+
+ /**
+ * Retrieves a stored long value.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @return Returns the preference value if it exists, or defValue.
+ * @throws ClassCastException if there is a preference with this name that is not a long.
+ * @see android.content.SharedPreferences#getLong(String, long)
+ */
+ public static long getLong(final String key, final long defValue) {
+ return getPreferences().getLong(key, defValue);
+ }
+
+ /**
+ * Returns the double that has been saved as a long raw bits value in the long preferences.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue the double Value to return if this preference does not exist.
+ * @return Returns the preference value if it exists, or defValue.
+ * @throws ClassCastException if there is a preference with this name that is not a long.
+ * @see android.content.SharedPreferences#getLong(String, long)
+ */
+ public static double getDouble(final String key, final double defValue) {
+ return Double.longBitsToDouble(getPreferences().getLong(key, Double.doubleToLongBits(defValue)));
+ }
+
+ /**
+ * Retrieves a stored float value.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @return Returns the preference value if it exists, or defValue.
+ * @throws ClassCastException if there is a preference with this name that is not a float.
+ * @see android.content.SharedPreferences#getFloat(String, float)
+ */
+ public static float getFloat(final String key, final float defValue) {
+ return getPreferences().getFloat(key, defValue);
+ }
+
+ /**
+ * Retrieves a stored String value.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @return Returns the preference value if it exists, or defValue.
+ * @throws ClassCastException if there is a preference with this name that is not a String.
+ * @see android.content.SharedPreferences#getString(String, String)
+ */
+ public static String getString(final String key, final String defValue) {
+ return getPreferences().getString(key, defValue);
+ }
+
+ /**
+ * Retrieves a Set of Strings as stored by {@link #putStringSet(String, Set)}. On Honeycomb and
+ * later this will call the native implementation in SharedPreferences, on older SDKs this will
+ * call {@link #getOrderedStringSet(String, Set)}.
+ * Note that the native implementation of {@link android.content.SharedPreferences#getStringSet(String,
+ * Set)} does not reliably preserve the order of the Strings in the Set.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @return Returns the preference values if they exist, or defValues otherwise.
+ * @throws ClassCastException if there is a preference with this name that is not a Set.
+ * @see android.content.SharedPreferences#getStringSet(String, Set)
+ * @see #getOrderedStringSet(String, Set)
+ */
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public static Set getStringSet(final String key, final Set defValue) {
+ android.content.SharedPreferences prefs = getPreferences();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ return prefs.getStringSet(key, defValue);
+ } else {
+ // Workaround for pre-HC's missing getStringSet
+ return getOrderedStringSet(key, defValue);
+ }
+ }
+
+ /**
+ * Retrieves a Set of Strings as stored by {@link #putOrderedStringSet(String, Set)},
+ * preserving the original order. Note that this implementation is heavier than the native
+ * {@link #getStringSet(String, Set)} method (which does not guarantee to preserve order).
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @return Returns the preference value if it exists, or defValues otherwise.
+ * @throws ClassCastException if there is a preference with this name that is not a Set of
+ * Strings.
+ * @see #getStringSet(String, Set)
+ */
+ public static Set getOrderedStringSet(String key, final Set defValue) {
+ android.content.SharedPreferences prefs = getPreferences();
+ if (prefs.contains(key + LENGTH)) {
+ LinkedHashSet set = new LinkedHashSet<>();
+ int stringSetLength = prefs.getInt(key + LENGTH, -1);
+ if (stringSetLength >= 0) {
+ for (int i = 0; i < stringSetLength; i++) {
+ set.add(prefs.getString(key + "[" + i + "]", null));
+ }
+ }
+ return set;
+ }
+ return defValue;
+ }
+
+ /**
+ * Stores a long value.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see Editor#putLong(String, long)
+ */
+ public static void putLong(final String key, final long value) {
+ final Editor editor = getPreferences().edit();
+ editor.putLong(key, value);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Stores an integer value.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see Editor#putInt(String, int)
+ */
+ public static void putInt(final String key, final int value) {
+ final Editor editor = getPreferences().edit();
+ editor.putInt(key, value);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Stores a double value as a long raw bits value.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The double value to be save in the preferences.
+ * @see Editor#putLong(String, long)
+ */
+ public static void putDouble(final String key, final double value) {
+ final Editor editor = getPreferences().edit();
+ editor.putLong(key, Double.doubleToRawLongBits(value));
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Stores a float value.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see Editor#putFloat(String, float)
+ */
+ public static void putFloat(final String key, final float value) {
+ final Editor editor = getPreferences().edit();
+ editor.putFloat(key, value);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Stores a boolean value.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see Editor#putBoolean(String, boolean)
+ */
+ public static void putBoolean(final String key, final boolean value) {
+ final Editor editor = getPreferences().edit();
+ editor.putBoolean(key, value);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Stores a String value.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see Editor#putString(String, String)
+ */
+ public static void putString(final String key, final String value) {
+ final Editor editor = getPreferences().edit();
+ editor.putString(key, value);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Stores a Set of Strings. On Honeycomb and later this will call the native implementation in
+ * SharedPreferences.Editor, on older SDKs this will call {@link #putOrderedStringSet(String,
+ * Set)}.
+ * Note that the native implementation of {@link Editor#putStringSet(String,
+ * Set)} does not reliably preserve the order of the Strings in the Set.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see Editor#putStringSet(String, Set)
+ * @see #putOrderedStringSet(String, Set)
+ */
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public static void putStringSet(final String key, final Set value) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ final Editor editor = getPreferences().edit();
+ editor.putStringSet(key, value);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ } else {
+ // Workaround for pre-HC's lack of StringSets
+ putOrderedStringSet(key, value);
+ }
+ }
+
+ /**
+ * Stores a Set of Strings, preserving the order.
+ * Note that this method is heavier that the native implementation {@link #putStringSet(String,
+ * Set)} (which does not reliably preserve the order of the Set). To preserve the order of the
+ * items in the Set, the Set implementation must be one that as an iterator with predictable
+ * order, such as {@link LinkedHashSet}.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see #putStringSet(String, Set)
+ * @see #getOrderedStringSet(String, Set)
+ */
+ public static void putOrderedStringSet(String key, Set value) {
+ final Editor editor = getPreferences().edit();
+ int stringSetLength = 0;
+ if (mPrefs.contains(key + LENGTH)) {
+ // First read what the value was
+ stringSetLength = mPrefs.getInt(key + LENGTH, -1);
+ }
+ editor.putInt(key + LENGTH, value.size());
+ int i = 0;
+ for (String aValue : value) {
+ editor.putString(key + "[" + i + "]", aValue);
+ i++;
+ }
+ for (; i < stringSetLength; i++) {
+ // Remove any remaining values
+ editor.remove(key + "[" + i + "]");
+ }
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Removes a preference value.
+ *
+ * @param key The name of the preference to remove.
+ * @see Editor#remove(String)
+ */
+ public static void remove(final String key) {
+ android.content.SharedPreferences prefs = getPreferences();
+ final Editor editor = prefs.edit();
+ if (prefs.contains(key + LENGTH)) {
+ // Workaround for pre-HC's lack of StringSets
+ int stringSetLength = prefs.getInt(key + LENGTH, -1);
+ if (stringSetLength >= 0) {
+ editor.remove(key + LENGTH);
+ for (int i = 0; i < stringSetLength; i++) {
+ editor.remove(key + "[" + i + "]");
+ }
+ }
+ }
+ editor.remove(key);
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Checks if a value is stored for the given key.
+ *
+ * @param key The name of the preference to check.
+ * @return {@code true} if the storage contains this key value, {@code false} otherwise.
+ * @see android.content.SharedPreferences#contains(String)
+ */
+ public static boolean contains(final String key) {
+ return getPreferences().contains(key);
+ }
+
+ /**
+ * Removed all the stored keys and values.
+ *
+ * @return the {@link Editor} for chaining. The changes have already been committed/applied
+ * through the execution of this method.
+ * @see Editor#clear()
+ */
+ public static Editor clear() {
+ final Editor editor = getPreferences().edit().clear();
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ return editor;
+ }
+
+ /**
+ * Returns the Editor of the underlying SharedPreferences instance.
+ *
+ * @return An Editor
+ */
+ public static Editor edit() {
+ return getPreferences().edit();
+ }
+
+ /**
+ * Builder class for the EasyPrefs instance. You only have to call this once in the Application
+ * onCreate. And in the rest of the code base you can call Prefs.method name.
+ */
+ public final static class Builder {
+
+ private String mKey;
+ private Context mContext;
+ private int mMode = -1;
+ private boolean mUseDefault = false;
+
+ /**
+ * Set the filename of the SharedPreference instance. Usually this is the application's
+ * packagename.xml but it can be modified for migration purposes or customization.
+ *
+ * @param prefsName the filename used for the SharedPreference
+ * @return the {@link SharedPreferences} object.
+ */
+ public Builder setPrefsName(final String prefsName) {
+ mKey = prefsName;
+ return this;
+ }
+
+ /**
+ * Set the Context used to instantiate the SharedPreferences
+ *
+ * @param context the application context
+ * @return the {@link SharedPreferences} object.
+ */
+ public Builder setContext(final Context context) {
+ mContext = context;
+ return this;
+ }
+
+ /**
+ * Set the mode of the SharedPreference instance.
+ *
+ * @param mode Operating mode. Use 0 or {@link Context#MODE_PRIVATE} for the
+ * default operation, {@link Context#MODE_WORLD_READABLE}
+ * @return the {@link SharedPreferences} object.
+ * @see Context#getSharedPreferences
+ */
+ public Builder setMode(final int mode) {
+ if (mode == ContextWrapper.MODE_PRIVATE || mode == ContextWrapper.MODE_WORLD_READABLE || mode == ContextWrapper.MODE_WORLD_WRITEABLE || mode == ContextWrapper.MODE_MULTI_PROCESS) {
+ mMode = mode;
+ } else {
+ throw new RuntimeException("The mode in the SharedPreference can only be set too ContextWrapper.MODE_PRIVATE, ContextWrapper.MODE_WORLD_READABLE, ContextWrapper.MODE_WORLD_WRITEABLE or ContextWrapper.MODE_MULTI_PROCESS");
+ }
+
+ return this;
+ }
+
+ /**
+ * Set the default SharedPreference file name. Often the package name of the application is
+ * used, but if the {@link android.preference.PreferenceActivity} or {@link
+ * android.preference.PreferenceFragment} is used the system will append that with
+ * _preference.
+ *
+ * @param defaultSharedPreference true if default SharedPreference name should used.
+ * @return the {@link SharedPreferences} object.
+ */
+ public Builder setUseDefaultSharedPreference(boolean defaultSharedPreference) {
+ mUseDefault = defaultSharedPreference;
+ return this;
+ }
+
+ /**
+ * Initialize the SharedPreference instance to used in the application.
+ *
+ * @throws RuntimeException if Context has not been set.
+ */
+ public void build() {
+ if (mContext == null) {
+ throw new RuntimeException("Context not set, please set context before building the Prefs instance.");
+ }
+
+ if (TextUtils.isEmpty(mKey)) {
+ mKey = mContext.getPackageName();
+ }
+
+ if (mUseDefault) {
+ mKey += DEFAULT_SUFFIX;
+ }
+
+ if (mMode == -1) {
+ mMode = ContextWrapper.MODE_PRIVATE;
+ }
+
+ SharedPreferences.initPrefs(mContext, mKey, mMode);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/validation/ValidationUtility.kt b/src/main/java/com/nativedevps/support/utility/validation/ValidationUtility.kt
new file mode 100644
index 0000000..6186ccb
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/validation/ValidationUtility.kt
@@ -0,0 +1,62 @@
+package com.nativedevps.support.utility.validation
+
+import android.content.Context
+import android.util.Patterns
+import android.widget.Toast
+import java.util.regex.Pattern
+
+/**
+ * Created by pchub on 29-09-2017.
+ *
+ * A Simple ValidationUtil class that can validate your inputs
+ * and can display the error messages on its own so that you
+ * don't have to bother adding multiple if-else-if statements
+ * and Toasts for your Validations.
+ *
+ * Of course you can modify this file according to your needs
+ * and implement more methods here to improve the validation of this class.
+ *
+ * *Note*
+ *
+ * Do not save your activity's context in this class as it will lead to memory leak.
+ * Only pass your activity's context to the parameters and avoid keeping reference
+ * of the activity stored inside this class.
+ *
+ */
+object ValidationUtility {
+
+ fun showToast(context: Context, message: String) = Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+
+ private fun isNullOrEmpty(input: String?): Boolean = input == null || input.isEmpty()
+
+ fun isValidUsername(username: String?, regex: String = "^[a-zA-Z0-9._-]{3,20}$"): Boolean {
+ return !isNullOrEmpty(username) &&
+ Pattern.matches(regex, username)
+ }
+
+ fun isValidEmail(email: String?): Boolean {
+ return !isNullOrEmpty(email) && Patterns.EMAIL_ADDRESS.matcher(email).matches()
+ }
+
+ fun isValidMobile(mobile: String?, regex: String = "^[0-9]{10}$"): Boolean {
+ return !isNullOrEmpty(mobile) && Pattern.matches(regex, mobile)
+ }
+
+ fun isValidPassword(password: String?): String? {
+ return when {
+ isNullOrEmpty(password) -> "Please enter Password first."
+ password!!.length < 6 -> "Password length should not be less than 6 characters"
+ password.length > 30 -> "Password length should not be greater than 30 characters"
+ else -> return null
+ }
+ }
+
+ fun isValidName(txtInput: String?): String? {
+ return when {
+ isNullOrEmpty(txtInput) -> "Please enter Name first."
+ txtInput!!.length < 4 -> "Name length should not be less than 4 characters"
+ txtInput.length > 30 -> "Name length should not be greater than 30 characters"
+ else -> return null
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/view/DialogBox.kt b/src/main/java/com/nativedevps/support/utility/view/DialogBox.kt
new file mode 100644
index 0000000..452a47f
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/view/DialogBox.kt
@@ -0,0 +1,68 @@
+package com.nativedevps.support.utility.view
+
+import android.app.Activity
+import androidx.appcompat.app.AlertDialog
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nativedevps.support.custom_views.ArrayDrawableListViewAdapter
+import nativedevps.support.databinding.DialogListBinding
+
+object DialogBox {
+ fun Activity.confirmationDialog(
+ title: String = "Alert",
+ message: String = "Are you sure?",
+ isCancellable: Boolean = true,
+ negativeText: String = "Cancel",
+ positiveText: String = "Ok",
+ callback: (success: Boolean) -> Unit,
+ ): AlertDialog {
+ val materialAlertDialogBuilder = MaterialAlertDialogBuilder(this)
+ materialAlertDialogBuilder.setTitle(title)
+ materialAlertDialogBuilder.setCancelable(isCancellable)
+ message.let {
+ materialAlertDialogBuilder.setMessage(it)
+ }
+ materialAlertDialogBuilder.setNegativeButton(negativeText) { dialog, which ->
+ materialAlertDialogBuilder.create().dismiss()
+ callback(false)
+ }
+ materialAlertDialogBuilder.setPositiveButton(positiveText) { dialog, which ->
+ materialAlertDialogBuilder.create().dismiss()
+ callback(true)
+ }
+ return materialAlertDialogBuilder.show()
+ }
+
+ fun Activity.listDialog(
+ title: String? = "Alert",
+ isCancellable: Boolean = true,
+ stringList: List>,
+ negativeText: String? = "Cancel",
+ callback: (success: Boolean, selection: Pair?) -> Unit,
+ ): AlertDialog {
+ var alertDialog: AlertDialog? = null
+ val binding = DialogListBinding.inflate(layoutInflater)
+ binding.itemsListView.adapter = ArrayDrawableListViewAdapter(this, stringList)
+ binding.itemsListView.setOnItemClickListener { adapterView, view, position, id ->
+ alertDialog?.dismiss()
+ callback(true, Pair(position, stringList[position].second))
+ }
+ val materialAlertDialogBuilder = MaterialAlertDialogBuilder(this)
+ materialAlertDialogBuilder.setView(binding.root)
+ materialAlertDialogBuilder.setTitle(title)
+ materialAlertDialogBuilder.setCancelable(isCancellable)
+
+ if (negativeText != null) {
+ materialAlertDialogBuilder.setNegativeButton(negativeText) { dialog, which ->
+ materialAlertDialogBuilder.create().dismiss()
+ callback(false, null)
+ }
+ }
+
+ return materialAlertDialogBuilder.show().apply {
+ alertDialog = this
+ alertDialog?.setOnCancelListener {
+ callback(false, null)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nativedevps/support/utility/view/ViewUtils.kt b/src/main/java/com/nativedevps/support/utility/view/ViewUtils.kt
new file mode 100644
index 0000000..f7d9ff0
--- /dev/null
+++ b/src/main/java/com/nativedevps/support/utility/view/ViewUtils.kt
@@ -0,0 +1,137 @@
+package com.nativedevps.support.utility.view
+
+import android.app.Activity
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.os.Build
+import android.os.SystemClock
+import android.view.*
+import android.widget.FrameLayout
+import android.widget.PopupWindow
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import androidx.annotation.RequiresApi
+
+
+object ViewUtils {
+ private const val TAG = "ViewUtils"
+ fun getViewFromLayout(mActivity: Activity, mContainerID: Int, mLayoutID: Int): View {
+ val activityContainer = mActivity.findViewById(mContainerID)
+ activityContainer.removeAllViews()
+ val vi = mActivity.layoutInflater.inflate(mLayoutID, null)
+ activityContainer.addView(vi)
+ return activityContainer
+ }
+
+ fun getViewFromLayout(
+ mActivity: Activity,
+ activityContainer: FrameLayout,
+ mLayoutID: Int,
+ ): View {
+ activityContainer.removeAllViews()
+ val vi = mActivity.layoutInflater.inflate(mLayoutID, null)
+ activityContainer.addView(vi)
+ return activityContainer
+ }
+
+ fun getViewFromLayout(mActivity: Activity, mLayoutID: Int): View {
+ return mActivity.layoutInflater.inflate(mLayoutID, null, false)
+ }
+
+ fun getSmoothAnimation(activity: Activity) {
+ activity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
+ }
+
+ fun setViewAndChildrenEnabled(view: View, enabled: Boolean) {
+ view.isEnabled = enabled
+ if (view is ViewGroup) {
+ val viewGroup = view
+ for (i in 0 until viewGroup.childCount) {
+ val child = viewGroup.getChildAt(i)
+ setViewAndChildrenEnabled(child, enabled)
+ }
+ }
+ }
+
+ fun getPopup(
+ mInstance: Activity?,
+ popupWindow: PopupWindow?,
+ contentView: View?,
+ anchorView: View?,
+ ): PopupWindow {
+ var popupWindow = popupWindow
+ if (popupWindow == null) {
+ popupWindow = PopupWindow(mInstance)
+ }
+ popupWindow.isFocusable = true
+ popupWindow.contentView = contentView
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ popupWindow.elevation = 5f
+ }
+ popupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ popupWindow.isOutsideTouchable = true
+ popupWindow.showAsDropDown(anchorView) // where u want show on view click event popupwindow.showAsDropDown(view, x, y);
+ return popupWindow
+ }
+
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ fun setStatusBarColor(activity: Activity, color: Int) {
+ val window: Window = activity.window
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+ window.setStatusBarColor(color)
+ }
+
+ fun TextView.setLeftDrawable(@DrawableRes drawable: Int) {
+ setCompoundDrawablesWithIntrinsicBounds(drawable, 0, 0, 0);
+ }
+
+ fun TextView.setTopDrawable(@DrawableRes drawable: Int) {
+ setCompoundDrawablesWithIntrinsicBounds(0, drawable, 0, 0);
+ }
+
+ fun TextView.setRightDrawable(@DrawableRes drawable: Int) {
+ setCompoundDrawablesWithIntrinsicBounds(0, 0, drawable, 0);
+ }
+
+ fun TextView.setBottomDrawable(@DrawableRes drawable: Int) {
+ setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, drawable);
+ }
+
+ fun View.setClickListener(onClickEvent: (view: View) -> Unit) {
+ this.setOnTouchListener { v, event ->
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ onClickEvent(v)
+ }
+ return@setOnTouchListener true
+ }
+ }
+
+ fun View.click() {
+ val downTime: Long = SystemClock.uptimeMillis()
+ val eventTime: Long = SystemClock.uptimeMillis() + 100
+ val x = 0.0f
+ val y = 0.0f
+ val metaState = 0
+ val motionEvent = MotionEvent.obtain(
+ downTime,
+ eventTime,
+ MotionEvent.ACTION_DOWN,
+ x,
+ y,
+ metaState
+ )
+ dispatchTouchEvent(motionEvent)
+ }
+
+ fun View.gone() {
+ this.visibility = View.GONE
+ }
+
+ fun View.visible() {
+ this.visibility = View.VISIBLE
+ }
+
+ fun View.invisible() {
+ this.visibility = View.INVISIBLE
+ }
+}
\ No newline at end of file
diff --git a/src/main/res/drawable/ic_baseline_account_balance_24.xml b/src/main/res/drawable/ic_baseline_account_balance_24.xml
new file mode 100644
index 0000000..97869be
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_account_balance_24.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_account_balance_wallet_24.xml b/src/main/res/drawable/ic_baseline_account_balance_wallet_24.xml
new file mode 100644
index 0000000..d90de7c
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_account_balance_wallet_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_add_24.xml b/src/main/res/drawable/ic_baseline_add_24.xml
new file mode 100644
index 0000000..bdd99f4
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_add_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_card_membership_24.xml b/src/main/res/drawable/ic_baseline_card_membership_24.xml
new file mode 100644
index 0000000..030c8ab
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_card_membership_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_credit_card_24.xml b/src/main/res/drawable/ic_baseline_credit_card_24.xml
new file mode 100644
index 0000000..9c0fb1f
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_credit_card_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_delete_24.xml b/src/main/res/drawable/ic_baseline_delete_24.xml
new file mode 100644
index 0000000..3c4030b
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_delete_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_language_24.xml b/src/main/res/drawable/ic_baseline_language_24.xml
new file mode 100644
index 0000000..3f70646
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_language_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_list_alt_24.xml b/src/main/res/drawable/ic_baseline_list_alt_24.xml
new file mode 100644
index 0000000..91683dc
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_list_alt_24.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_logout_24.xml b/src/main/res/drawable/ic_baseline_logout_24.xml
new file mode 100644
index 0000000..2059dea
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_logout_24.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_schema_24.xml b/src/main/res/drawable/ic_baseline_schema_24.xml
new file mode 100644
index 0000000..0257349
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_schema_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/drawable/ic_baseline_settings_24.xml b/src/main/res/drawable/ic_baseline_settings_24.xml
new file mode 100644
index 0000000..41a82ed
--- /dev/null
+++ b/src/main/res/drawable/ic_baseline_settings_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/drawable/ic_round_contact_page_24.xml b/src/main/res/drawable/ic_round_contact_page_24.xml
new file mode 100644
index 0000000..b461e4c
--- /dev/null
+++ b/src/main/res/drawable/ic_round_contact_page_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/src/main/res/drawable/ic_round_person_24.xml b/src/main/res/drawable/ic_round_person_24.xml
new file mode 100644
index 0000000..64194a2
--- /dev/null
+++ b/src/main/res/drawable/ic_round_person_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/main/res/layout/activity_actionbar.xml b/src/main/res/layout/activity_actionbar.xml
new file mode 100644
index 0000000..82c2cd8
--- /dev/null
+++ b/src/main/res/layout/activity_actionbar.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/d_progress_bar.xml b/src/main/res/layout/d_progress_bar.xml
new file mode 100644
index 0000000..e88dfa9
--- /dev/null
+++ b/src/main/res/layout/d_progress_bar.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/dialog_list.xml b/src/main/res/layout/dialog_list.xml
new file mode 100644
index 0000000..c23ecf2
--- /dev/null
+++ b/src/main/res/layout/dialog_list.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/item_simple_list_view.xml b/src/main/res/layout/item_simple_list_view.xml
new file mode 100644
index 0000000..04e895a
--- /dev/null
+++ b/src/main/res/layout/item_simple_list_view.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml
new file mode 100644
index 0000000..4a893b7
--- /dev/null
+++ b/src/main/res/values/colors.xml
@@ -0,0 +1,19 @@
+
+
+ #00000000
+ #CACACA
+ #88979797
+ #B3000000
+ #FFF0E8
+ #88FFF9F5
+ #F7F7F7\
+ #66000000
+ #40000000
+ #454242
+ #32e6e6e6
+ #FFFFFF
+ #00C853
+ #eceff1
+ #000000
+ #0645AD
+
\ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
new file mode 100644
index 0000000..a54ed69
--- /dev/null
+++ b/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ support
+
\ No newline at end of file
diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml
new file mode 100644
index 0000000..6a774d1
--- /dev/null
+++ b/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+