diff --git a/app/build.gradle b/app/build.gradle index e31ed1f..2d29051 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,7 +4,7 @@ android { compileSdkVersion 28 defaultConfig { applicationId "com.example.negar.testone" - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.0" diff --git a/app/src/main/java/com/Vasl/Library/Android/LocaleHelper.java b/app/src/main/java/com/Vasl/Library/Android/LocaleHelper.java new file mode 100644 index 0000000..79a0ef2 --- /dev/null +++ b/app/src/main/java/com/Vasl/Library/Android/LocaleHelper.java @@ -0,0 +1,72 @@ +package com.Vasl.Library.Android; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Build; + +import java.util.Locale; + +/** + * Created by Reza Amozadeh on 4/9/2017. + */ + +public class LocaleHelper { + + private static String LocalizationEN = "en"; + + private static String LocalizationFA = "fa"; + + public static void onAttach(Context context) { + LocaleHelper.setLocal(context); + } + + public static void onAttach(Context context, String defaultLanguage) { + LocaleHelper.setLocal(context, defaultLanguage); + } + + @SuppressWarnings("deprecation") + public static void setSystemLocaleLegacy(Configuration config, Locale locale) { + config.locale = locale; + } + + @TargetApi(Build.VERSION_CODES.N) + public static void setSystemLocale(Configuration config, Locale locale) { + config.setLocale(locale); + } + + public static void setLocal(Context context) { + setLocal(context, getLanguageSetting(context)); + } + + private static String getLanguageSetting(Context context) { + return LocalizationFA; + } + + public static void setLocal(Context context, String language) { + Locale locale = new Locale(language); + Locale.setDefault(locale); + + Configuration config = new Configuration(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + setSystemLocale(config, locale); + } else { + setSystemLocaleLegacy(config, locale); + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + context.getApplicationContext().getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); + } else { + context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); + } + } + + public static String getLocal() { + Locale localHelper = Locale.getDefault(); + return localHelper.getLanguage(); + } + + public static Boolean isRTL() { + return getLocal().equals(LocalizationFA); + } + +} diff --git a/app/src/main/java/com/Vasl/Library/Android/MainActivity.java b/app/src/main/java/com/Vasl/Library/Android/MainActivity.java index 102541f..7f1e595 100644 --- a/app/src/main/java/com/Vasl/Library/Android/MainActivity.java +++ b/app/src/main/java/com/Vasl/Library/Android/MainActivity.java @@ -1,5 +1,6 @@ package com.Vasl.Library.Android; +import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.view.Menu; @@ -45,6 +46,12 @@ public void run() { } + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(newBase); + LocaleHelper.onAttach(newBase); + } + private void myList() { myCustomView.setStatus(ListStatuse.LOADING, null); @@ -106,16 +113,16 @@ public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.action_load: - myCustomView.setStatus(ListStatuse.LOADING, null); + myCustomView.setStatus(ListStatuse.LOADING); return true; case R.id.action_success: - myCustomView.setStatus(ListStatuse.SUCCESS, null); + myCustomView.setStatus(ListStatuse.SUCCESS); return true; case R.id.action_failure: - myCustomView.setStatus(ListStatuse.FAILURE, "hellooo"); + myCustomView.setStatus(ListStatuse.FAILURE); return true; case R.id.action_empty: - myCustomView.setStatus(ListStatuse.EMPTY, "no item"); + myCustomView.setStatus(ListStatuse.EMPTY); return true; } return false; diff --git a/recyclerlibrary/build.gradle b/recyclerlibrary/build.gradle index 195cbf2..4e8a603 100644 --- a/recyclerlibrary/build.gradle +++ b/recyclerlibrary/build.gradle @@ -4,7 +4,7 @@ android { compileSdkVersion 28 defaultConfig { - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.0" @@ -19,21 +19,26 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + // SUPPORT LIBRARY implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'com.github.bumptech.glide:glide:4.8.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'com.wang.avi:library:2.1.3' - testImplementation 'junit:junit:4.12' + // OTHERS + implementation 'com.github.bumptech.glide:glide:4.8.0' + implementation 'com.tuyenmonkey:mkloader:1.4.0' + + // ANNOTATIONS annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' + + // TESTS + testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' diff --git a/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/MyCustomView.java b/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/MyCustomView.java index 690d935..ccc874d 100644 --- a/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/MyCustomView.java +++ b/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/MyCustomView.java @@ -5,6 +5,7 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.Button; +import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.Vasl.recyclerlibrary.globalEnums.ListStatuse; @@ -16,24 +17,24 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -public class MyCustomView extends RelativeLayout implements View.OnClickListener - , SwipeRefreshLayout.OnRefreshListener { +public class MyCustomView extends RelativeLayout + implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener { Context context; // layout_loading - RelativeLayout loading; + LinearLayout loading; // recycler view RecyclerView recyclerView; // empty view - RelativeLayout emptyHolder; - AppCompatTextView emptyTextView; + LinearLayout emptyHolder; + AppCompatTextView emptyTextViewTitle, emptyTextViewSubTitle; // error view - RelativeLayout errorHolder; - AppCompatTextView errorTextView; + LinearLayout errorHolder; + AppCompatTextView errorTextViewTitle, errorTextViewSubTitle; Button buttonRetry; // swipe @@ -73,18 +74,25 @@ public void init() { buttonRetry = view.findViewById(R.id.button_retry); buttonRetry.setOnClickListener(this); + // loading-view loading = view.findViewById(R.id.loadingHolder); + // recycler-view recyclerView = view.findViewById(R.id.recyclerView); + // swipe-view swipeRefreshLayout = view.findViewById(R.id.swipeHolder); swipeRefreshLayout.setOnRefreshListener(this); + // empty-view emptyHolder = view.findViewById(R.id.emptyHolder); - emptyTextView = view.findViewById(R.id.emptyTextView); + emptyTextViewTitle = view.findViewById(R.id.emptyTextViewTitle); + emptyTextViewSubTitle = view.findViewById(R.id.emptyTextViewSubTitle); + //error-view errorHolder = view.findViewById(R.id.errorHolder); - errorTextView = view.findViewById(R.id.errorTextView); + errorTextViewTitle = view.findViewById(R.id.errorTextViewTitle); + errorTextViewSubTitle = view.findViewById(R.id.errorTextViewSubTitle); } @@ -96,15 +104,27 @@ private void showLoading() { loading.setVisibility(VISIBLE); } - private void setErrorMsg(String msg){ - if (!PublicFunction.StringIsEmptyOrNull(msg)) { - errorTextView.setText(msg); + private void setErrorTitle(@Nullable String title) { + if (!PublicFunction.StringIsEmptyOrNull(title)) { + errorTextViewTitle.setText(title); } } - private void setEmtpyMsg(String msg){ - if (!PublicFunction.StringIsEmptyOrNull(msg)) { - emptyTextView.setText(msg); + private void setErrorSubTitle(@Nullable String subTitle) { + if (!PublicFunction.StringIsEmptyOrNull(subTitle)) { + errorTextViewSubTitle.setText(subTitle); + } + } + + private void setEmptyTitle(@Nullable String title) { + if (!PublicFunction.StringIsEmptyOrNull(title)) { + emptyTextViewTitle.setText(title); + } + } + + private void setEmptySubTitle(@Nullable String subtitle) { + if (!PublicFunction.StringIsEmptyOrNull(subtitle)) { + emptyTextViewSubTitle.setText(subtitle); } } @@ -144,7 +164,7 @@ private void hideError() { errorHolder.setVisibility(GONE); } - public void setStatus(ListStatuse status,@Nullable String error) { + public void setStatus(ListStatuse status) { switch (status) { case LOADING: showLoading(); @@ -165,7 +185,7 @@ public void setStatus(ListStatuse status,@Nullable String error) { hideEmptyView(); hideRecyclerView(); hideSwipe(); - setErrorMsg(error); + setErrorTitle(null); showError(); break; case EMPTY: @@ -173,7 +193,7 @@ public void setStatus(ListStatuse status,@Nullable String error) { hideRecyclerView(); hideSwipe(); hideError(); - setEmtpyMsg(error); + setEmptyTitle(null); showEmptyView(); break; case UNDEFINE: @@ -193,6 +213,54 @@ public void setStatus(ListStatuse status,@Nullable String error) { } } + public void setStatus(ListStatuse status, @Nullable String title) { + switch (status) { + case LOADING: + showLoading(); + hideEmptyView(); + hideRecyclerView(); + hideSwipe(); + hideError(); + break; + case SUCCESS: + hideLoading(); + hideEmptyView(); + showRecyclerView(); + hideSwipe(); + hideError(); + break; + case FAILURE: + hideLoading(); + hideEmptyView(); + hideRecyclerView(); + hideSwipe(); + setErrorTitle(title); + showError(); + break; + case EMPTY: + hideLoading(); + hideRecyclerView(); + hideSwipe(); + hideError(); + setEmptyTitle(title); + showEmptyView(); + break; + case UNDEFINE: + hideLoading(); + hideEmptyView(); + hideRecyclerView(); + hideSwipe(); + showError(); + break; + default: + hideLoading(); + hideEmptyView(); + hideRecyclerView(); + hideSwipe(); + showError(); + break; + } + } @Override public void onRefresh() { diff --git a/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/customViews/CustomImageView.java b/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/customViews/CustomImageView.java index ae4cae3..5fe81f9 100644 --- a/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/customViews/CustomImageView.java +++ b/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/customViews/CustomImageView.java @@ -2,15 +2,18 @@ import android.content.Context; import android.content.res.TypedArray; -import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import com.Vasl.recyclerlibrary.R; +import androidx.appcompat.widget.AppCompatImageView; + public class CustomImageView extends AppCompatImageView { - boolean isCircle; - String gravity; + private boolean isCircle; + + private String gravity; + private Context context; public CustomImageView(Context context) { @@ -19,6 +22,13 @@ public CustomImageView(Context context) { init(); } + public CustomImageView(Context context, boolean isCircle) { + super(context); + this.context = context; + this.isCircle = isCircle; + init(); + } + public CustomImageView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; diff --git a/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/customViews/CustomLoading.java b/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/customViews/CustomLoading.java deleted file mode 100644 index 637fe7c..0000000 --- a/recyclerlibrary/src/main/java/com/Vasl/recyclerlibrary/customViews/CustomLoading.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.Vasl.recyclerlibrary.customViews; - -import android.content.Context; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import android.util.AttributeSet; - -import com.wang.avi.AVLoadingIndicatorView; - -public class CustomLoading extends SwipeRefreshLayout { - - - private Context context; - private AVLoadingIndicatorView av; - - public CustomLoading(Context context) { - super(context); - this.context = context; - } - - public CustomLoading(Context context, AttributeSet attrs) { - super(context, attrs); - this.context = context; - init(); - } - - public void init() { - av = new AVLoadingIndicatorView(getContext()); - av.setIndicator("LineSpinFadeLoaderIndicator"); - - - } -} diff --git a/recyclerlibrary/src/main/res/drawable/empty_256.png b/recyclerlibrary/src/main/res/drawable/empty_256.png new file mode 100644 index 0000000..f301379 Binary files /dev/null and b/recyclerlibrary/src/main/res/drawable/empty_256.png differ diff --git a/recyclerlibrary/src/main/res/drawable/no_wifi_256.png b/recyclerlibrary/src/main/res/drawable/no_wifi_256.png new file mode 100644 index 0000000..730be60 Binary files /dev/null and b/recyclerlibrary/src/main/res/drawable/no_wifi_256.png differ diff --git a/recyclerlibrary/src/main/res/drawable/retry_button_background.xml b/recyclerlibrary/src/main/res/drawable/retry_button_background.xml index 3980481..8a4f67e 100644 --- a/recyclerlibrary/src/main/res/drawable/retry_button_background.xml +++ b/recyclerlibrary/src/main/res/drawable/retry_button_background.xml @@ -2,12 +2,12 @@ - + + android:startColor="#3e96f2" /> \ No newline at end of file diff --git a/recyclerlibrary/src/main/res/font/app_font.xml b/recyclerlibrary/src/main/res/font/app_font.xml new file mode 100644 index 0000000..dbdea28 --- /dev/null +++ b/recyclerlibrary/src/main/res/font/app_font.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/recyclerlibrary/src/main/res/font/iran_sans_light.ttf b/recyclerlibrary/src/main/res/font/iran_sans_light.ttf new file mode 100644 index 0000000..9ec3d9c Binary files /dev/null and b/recyclerlibrary/src/main/res/font/iran_sans_light.ttf differ diff --git a/recyclerlibrary/src/main/res/layout/layout_empty.xml b/recyclerlibrary/src/main/res/layout/layout_empty.xml index 6805d81..1bce123 100644 --- a/recyclerlibrary/src/main/res/layout/layout_empty.xml +++ b/recyclerlibrary/src/main/res/layout/layout_empty.xml @@ -1,26 +1,30 @@ - + android:gravity="center" + android:orientation="vertical" + android:visibility="gone"> + android:layout_width="150dp" + android:layout_height="150dp" + android:src="@drawable/empty_256" /> + android:text="@string/Oops" /> - \ No newline at end of file + + + \ No newline at end of file diff --git a/recyclerlibrary/src/main/res/layout/layout_error.xml b/recyclerlibrary/src/main/res/layout/layout_error.xml index 9397ddd..00471c3 100644 --- a/recyclerlibrary/src/main/res/layout/layout_error.xml +++ b/recyclerlibrary/src/main/res/layout/layout_error.xml @@ -1,12 +1,11 @@ - + android:visibility="gone"> - + - + - + + + - \ No newline at end of file + \ No newline at end of file diff --git a/recyclerlibrary/src/main/res/layout/layout_loading.xml b/recyclerlibrary/src/main/res/layout/layout_loading.xml index 325195e..dd3e8ba 100644 --- a/recyclerlibrary/src/main/res/layout/layout_loading.xml +++ b/recyclerlibrary/src/main/res/layout/layout_loading.xml @@ -1,29 +1,31 @@ - - + + + android:text="@string/loading_title" /> + android:text="@string/loading_sub_title" /> - \ No newline at end of file + \ No newline at end of file diff --git a/recyclerlibrary/src/main/res/layout/layout_my_custom_view.xml b/recyclerlibrary/src/main/res/layout/layout_my_custom_view.xml index c20a34e..35f2232 100644 --- a/recyclerlibrary/src/main/res/layout/layout_my_custom_view.xml +++ b/recyclerlibrary/src/main/res/layout/layout_my_custom_view.xml @@ -1,6 +1,5 @@ - @@ -20,7 +19,7 @@ - + diff --git a/recyclerlibrary/src/main/res/mipmap-hdpi/jp_noitem.png b/recyclerlibrary/src/main/res/mipmap-hdpi/jp_noitem.png deleted file mode 100644 index c98321d..0000000 Binary files a/recyclerlibrary/src/main/res/mipmap-hdpi/jp_noitem.png and /dev/null differ diff --git a/recyclerlibrary/src/main/res/mipmap-mdpi/jp_noitem.png b/recyclerlibrary/src/main/res/mipmap-mdpi/jp_noitem.png deleted file mode 100644 index 5139ac1..0000000 Binary files a/recyclerlibrary/src/main/res/mipmap-mdpi/jp_noitem.png and /dev/null differ diff --git a/recyclerlibrary/src/main/res/mipmap-xhdpi/jp_noitem.png b/recyclerlibrary/src/main/res/mipmap-xhdpi/jp_noitem.png deleted file mode 100644 index 5139ac1..0000000 Binary files a/recyclerlibrary/src/main/res/mipmap-xhdpi/jp_noitem.png and /dev/null differ diff --git a/recyclerlibrary/src/main/res/mipmap-xxhdpi/jp_noitem.png b/recyclerlibrary/src/main/res/mipmap-xxhdpi/jp_noitem.png deleted file mode 100644 index 9bf9bf1..0000000 Binary files a/recyclerlibrary/src/main/res/mipmap-xxhdpi/jp_noitem.png and /dev/null differ diff --git a/recyclerlibrary/src/main/res/mipmap-xxxhdpi/jp_noitem.png b/recyclerlibrary/src/main/res/mipmap-xxxhdpi/jp_noitem.png deleted file mode 100644 index 788a818..0000000 Binary files a/recyclerlibrary/src/main/res/mipmap-xxxhdpi/jp_noitem.png and /dev/null differ diff --git a/recyclerlibrary/src/main/res/values-fa/strings.xml b/recyclerlibrary/src/main/res/values-fa/strings.xml index cb3435a..5180e03 100644 --- a/recyclerlibrary/src/main/res/values-fa/strings.xml +++ b/recyclerlibrary/src/main/res/values-fa/strings.xml @@ -1,7 +1,15 @@ + recyclerLibrary فیلدی برای نمایش وجود ندارد اتفاق بدی افتاده تلاش مجدد - Loading ... + بارگذاری + عجب! + لیست مورد نظر شما خالی است + خطا! + اشکالی پیش آمده، لطفا مجدد تلاش کنید + بارگذاری + لطفا چند لحظه صبر کنید + diff --git a/recyclerlibrary/src/main/res/values/strings.xml b/recyclerlibrary/src/main/res/values/strings.xml index d7e002e..2405332 100644 --- a/recyclerlibrary/src/main/res/values/strings.xml +++ b/recyclerlibrary/src/main/res/values/strings.xml @@ -4,4 +4,10 @@ some thing bad happened! ;) Retry Loading ... + Oops! + Your list is empty, \n so there is nothing to show here. + UH OH! + Something went wrong, \n please try again + Loading + Please wait until request complete diff --git a/recyclerlibrary/src/main/res/values/styles.xml b/recyclerlibrary/src/main/res/values/styles.xml index fd3baa5..d2bec88 100644 --- a/recyclerlibrary/src/main/res/values/styles.xml +++ b/recyclerlibrary/src/main/res/values/styles.xml @@ -15,11 +15,31 @@ @color/colorPrimary - + + + + +