Add kotlin support and remove detailed view
This commit is contained in:
parent
b72fd0ee6f
commit
c7ba826132
9 changed files with 33 additions and 384 deletions
|
@ -1,4 +1,5 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.3.31'
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
|
@ -6,8 +7,9 @@ buildscript {
|
|||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.android.tools.build:gradle:3.4.1'
|
||||
classpath 'com.jakewharton:butterknife-gradle-plugin:10.1.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Sat Mar 09 10:49:30 CET 2019
|
||||
#Thu May 30 15:47:28 CEST 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'com.jakewharton.butterknife'
|
||||
|
||||
android {
|
||||
|
@ -8,14 +10,8 @@ android {
|
|||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
versionCode 9
|
||||
versionName "1.0.8"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
versionCode 10
|
||||
versionName "2.0.0"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
|
@ -25,13 +21,14 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "androidx.appcompat:appcompat:1.0.2"
|
||||
implementation "androidx.recyclerview:recyclerview:1.0.0"
|
||||
implementation "com.google.android.material:material:1.0.0"
|
||||
implementation "androidx.core:core-ktx:1.0.2"
|
||||
|
||||
implementation 'com.beloo.widget:ChipsLayoutManager:0.3.7@aar'
|
||||
implementation "androidx.recyclerview:recyclerview:1.0.0"
|
||||
implementation "com.google.android.material:material:1.1.0-alpha07"
|
||||
implementation 'de.hdodenhof:circleimageview:3.0.0'
|
||||
implementation 'com.beloo.widget:ChipsLayoutManager:0.3.7@aar'
|
||||
|
||||
implementation 'com.jakewharton:butterknife:10.1.0'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
|
||||
|
|
|
@ -11,6 +11,9 @@ import android.util.AttributeSet;
|
|||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager;
|
||||
import com.pchmn.materialchips.adapter.ChipsAdapter;
|
||||
import com.pchmn.materialchips.model.Chip;
|
||||
|
@ -20,14 +23,11 @@ import com.pchmn.materialchips.util.MyWindowCallback;
|
|||
import com.pchmn.materialchips.util.SmoothScrollLinearLayoutManager;
|
||||
import com.pchmn.materialchips.util.ViewUtil;
|
||||
import com.pchmn.materialchips.views.ChipsInputEditText;
|
||||
import com.pchmn.materialchips.views.DetailedChipView;
|
||||
import com.pchmn.materialchips.views.FilterableListView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
|
@ -230,15 +230,6 @@ public class ChipsInput extends FrameLayout {
|
|||
return editText;
|
||||
}
|
||||
|
||||
public DetailedChipView getDetailedChipView(ChipInterface chip) {
|
||||
return new DetailedChipView.Builder(mContext)
|
||||
.chip(chip)
|
||||
.textColor(mChipDetailedTextColor)
|
||||
.backgroundColor(mChipDetailedBackgroundColor)
|
||||
.deleteIconColor(mChipDetailedDeleteIconColor)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void addChipsListener(ChipsListener chipsListener) {
|
||||
mChipsListenerList.add(chipsListener);
|
||||
mChipsListener = chipsListener;
|
||||
|
|
|
@ -13,20 +13,19 @@ import android.view.inputmethod.EditorInfo;
|
|||
import android.widget.EditText;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.pchmn.materialchips.ChipView;
|
||||
import com.pchmn.materialchips.ChipsInput;
|
||||
import com.pchmn.materialchips.model.ChipInterface;
|
||||
import com.pchmn.materialchips.util.ViewUtil;
|
||||
import com.pchmn.materialchips.views.ChipsInputEditText;
|
||||
import com.pchmn.materialchips.views.DetailedChipView;
|
||||
import com.pchmn.materialchips.views.FilterableListView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
||||
public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
|
@ -205,66 +204,6 @@ public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
removeChip(position);
|
||||
}
|
||||
});
|
||||
|
||||
// show detailed chip
|
||||
if (mChipsInput.isShowChipDetailed()) {
|
||||
chipView.setOnChipClicked(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// get chip position
|
||||
int[] coord = new int[2];
|
||||
v.getLocationInWindow(coord);
|
||||
|
||||
final DetailedChipView detailedChipView = mChipsInput.getDetailedChipView(getItem(position));
|
||||
setDetailedChipViewPosition(detailedChipView, coord);
|
||||
|
||||
// delete button
|
||||
detailedChipView.setOnDeleteClicked(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
removeChip(position);
|
||||
detailedChipView.fadeOut();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setDetailedChipViewPosition(DetailedChipView detailedChipView, int[] coord) {
|
||||
// window width
|
||||
ViewGroup rootView = (ViewGroup) mRecycler.getRootView();
|
||||
int windowWidth = ViewUtil.getWindowWidth(mContext);
|
||||
|
||||
// chip size
|
||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
|
||||
ViewUtil.dpToPx(300),
|
||||
ViewUtil.dpToPx(100));
|
||||
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
|
||||
// align left window
|
||||
if (coord[0] <= 0) {
|
||||
layoutParams.leftMargin = 0;
|
||||
layoutParams.topMargin = coord[1] - ViewUtil.dpToPx(13);
|
||||
detailedChipView.alignLeft();
|
||||
}
|
||||
// align right
|
||||
else if (coord[0] + ViewUtil.dpToPx(300) > windowWidth + ViewUtil.dpToPx(13)) {
|
||||
layoutParams.leftMargin = windowWidth - ViewUtil.dpToPx(300);
|
||||
layoutParams.topMargin = coord[1] - ViewUtil.dpToPx(13);
|
||||
detailedChipView.alignRight();
|
||||
}
|
||||
// same position as chip
|
||||
else {
|
||||
layoutParams.leftMargin = coord[0] - ViewUtil.dpToPx(13);
|
||||
layoutParams.topMargin = coord[1] - ViewUtil.dpToPx(13);
|
||||
}
|
||||
|
||||
// show view
|
||||
rootView.addView(detailedChipView, layoutParams);
|
||||
detailedChipView.fadeIn();
|
||||
}
|
||||
|
||||
public void setFilterableListView(FilterableListView filterableListView) {
|
||||
|
|
|
@ -16,12 +16,11 @@ import android.view.WindowManager;
|
|||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.pchmn.materialchips.views.ChipsInputEditText;
|
||||
import com.pchmn.materialchips.views.DetailedChipView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.pchmn.materialchips.views.ChipsInputEditText;
|
||||
|
||||
public class MyWindowCallback implements Window.Callback {
|
||||
|
||||
private Window.Callback mLocalCallback;
|
||||
|
@ -46,13 +45,6 @@ public class MyWindowCallback implements Window.Callback {
|
|||
public boolean dispatchTouchEvent(MotionEvent motionEvent) {
|
||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
View v = mActivity.getCurrentFocus();
|
||||
if(v instanceof DetailedChipView) {
|
||||
Rect outRect = new Rect();
|
||||
v.getGlobalVisibleRect(outRect);
|
||||
if (!outRect.contains((int) motionEvent.getRawX(), (int) motionEvent.getRawY())) {
|
||||
((DetailedChipView) v).fadeOut();
|
||||
}
|
||||
}
|
||||
if (v instanceof ChipsInputEditText) {
|
||||
Rect outRect = new Rect();
|
||||
v.getGlobalVisibleRect(outRect);
|
||||
|
|
|
@ -1,276 +0,0 @@
|
|||
package com.pchmn.materialchips.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.pchmn.materialchips.R;
|
||||
import com.pchmn.materialchips.R2;
|
||||
import com.pchmn.materialchips.model.ChipInterface;
|
||||
import com.pchmn.materialchips.util.ColorUtil;
|
||||
import com.pchmn.materialchips.util.LetterTileProvider;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
|
||||
public class DetailedChipView extends RelativeLayout {
|
||||
|
||||
private static final String TAG = DetailedChipView.class.toString();
|
||||
// context
|
||||
private Context mContext;
|
||||
// xml elements
|
||||
@BindView(R2.id.content)
|
||||
RelativeLayout mContentLayout;
|
||||
@BindView(R2.id.avatar_icon)
|
||||
CircleImageView mAvatarIconImageView;
|
||||
@BindView(R2.id.name)
|
||||
TextView mNameTextView;
|
||||
@BindView(R2.id.info)
|
||||
TextView mInfoTextView;
|
||||
@BindView(R2.id.delete_button)
|
||||
ImageButton mDeleteButton;
|
||||
// letter tile provider
|
||||
private static LetterTileProvider mLetterTileProvider;
|
||||
// attributes
|
||||
private ColorStateList mBackgroundColor;
|
||||
|
||||
public DetailedChipView(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
init(null);
|
||||
}
|
||||
|
||||
public DetailedChipView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflate the view according to attributes
|
||||
*
|
||||
* @param attrs the attributes
|
||||
*/
|
||||
private void init(AttributeSet attrs) {
|
||||
// inflate layout
|
||||
View rootView = inflate(getContext(), R.layout.detailed_chip_view, this);
|
||||
// butter knife
|
||||
ButterKnife.bind(this, rootView);
|
||||
// letter tile provider
|
||||
mLetterTileProvider = new LetterTileProvider(mContext);
|
||||
|
||||
// hide on first
|
||||
setVisibility(GONE);
|
||||
// hide on touch outside
|
||||
hideOnTouchOutside();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the view on touch outside of it
|
||||
*/
|
||||
private void hideOnTouchOutside() {
|
||||
// set focusable
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
setClickable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade in
|
||||
*/
|
||||
public void fadeIn() {
|
||||
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
|
||||
anim.setDuration(200);
|
||||
startAnimation(anim);
|
||||
setVisibility(VISIBLE);
|
||||
// focus on the view
|
||||
requestFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade out
|
||||
*/
|
||||
public void fadeOut() {
|
||||
AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
|
||||
anim.setDuration(200);
|
||||
startAnimation(anim);
|
||||
setVisibility(GONE);
|
||||
// fix onclick issue
|
||||
clearFocus();
|
||||
setClickable(false);
|
||||
}
|
||||
|
||||
public void setAvatarIcon(Drawable icon) {
|
||||
mAvatarIconImageView.setImageDrawable(icon);
|
||||
}
|
||||
|
||||
public void setAvatarIcon(Bitmap icon) {
|
||||
mAvatarIconImageView.setImageBitmap(icon);
|
||||
}
|
||||
|
||||
public void setAvatarIcon(Uri icon) {
|
||||
mAvatarIconImageView.setImageURI(icon);
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
mNameTextView.setText(name);
|
||||
}
|
||||
|
||||
public void setInfo(String info) {
|
||||
if (info != null) {
|
||||
mInfoTextView.setVisibility(VISIBLE);
|
||||
mInfoTextView.setText(info);
|
||||
} else {
|
||||
mInfoTextView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTextColor(ColorStateList color) {
|
||||
mNameTextView.setTextColor(color);
|
||||
mInfoTextView.setTextColor(ColorUtil.alpha(color.getDefaultColor(), 150));
|
||||
}
|
||||
|
||||
public void setBackgroundColor(ColorStateList color) {
|
||||
mBackgroundColor = color;
|
||||
mContentLayout.getBackground().setColorFilter(color.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
TypedArray array = mContext.obtainStyledAttributes(null, new int[]{R.attr.colorAccent});
|
||||
try {
|
||||
return mBackgroundColor == null ? array.getColor(0, 0) : mBackgroundColor.getDefaultColor();
|
||||
} finally {
|
||||
array.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDeleteIconColor(ColorStateList color) {
|
||||
mDeleteButton.getDrawable().mutate().setColorFilter(color.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
public void setOnDeleteClicked(OnClickListener onClickListener) {
|
||||
mDeleteButton.setOnClickListener(onClickListener);
|
||||
}
|
||||
|
||||
public void alignLeft() {
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mContentLayout.getLayoutParams();
|
||||
params.leftMargin = 0;
|
||||
mContentLayout.setLayoutParams(params);
|
||||
}
|
||||
|
||||
public void alignRight() {
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mContentLayout.getLayoutParams();
|
||||
params.rightMargin = 0;
|
||||
mContentLayout.setLayoutParams(params);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Context context;
|
||||
private Uri avatarUri;
|
||||
private Drawable avatarDrawable;
|
||||
private String name;
|
||||
private String info;
|
||||
private ColorStateList textColor;
|
||||
private ColorStateList backgroundColor;
|
||||
private ColorStateList deleteIconColor;
|
||||
|
||||
public Builder(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Builder avatar(Uri avatarUri) {
|
||||
this.avatarUri = avatarUri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder avatar(Drawable avatarDrawable) {
|
||||
this.avatarDrawable = avatarDrawable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder info(String info) {
|
||||
this.info = info;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder chip(ChipInterface chip) {
|
||||
this.avatarUri = chip.getAvatarUri();
|
||||
this.avatarDrawable = chip.getAvatarDrawable();
|
||||
this.name = chip.getLabel();
|
||||
this.info = chip.getInfo();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder textColor(ColorStateList textColor) {
|
||||
this.textColor = textColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder backgroundColor(ColorStateList backgroundColor) {
|
||||
this.backgroundColor = backgroundColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder deleteIconColor(ColorStateList deleteIconColor) {
|
||||
this.deleteIconColor = deleteIconColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DetailedChipView build() {
|
||||
return DetailedChipView.newInstance(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static DetailedChipView newInstance(Builder builder) {
|
||||
DetailedChipView detailedChipView = new DetailedChipView(builder.context);
|
||||
// avatar
|
||||
if (builder.avatarUri != null)
|
||||
detailedChipView.setAvatarIcon(builder.avatarUri);
|
||||
else if (builder.avatarDrawable != null)
|
||||
detailedChipView.setAvatarIcon(builder.avatarDrawable);
|
||||
else
|
||||
detailedChipView.setAvatarIcon(mLetterTileProvider.getLetterTile(builder.name));
|
||||
|
||||
// background color
|
||||
if (builder.backgroundColor != null)
|
||||
detailedChipView.setBackgroundColor(builder.backgroundColor);
|
||||
|
||||
// text color
|
||||
if (builder.textColor != null)
|
||||
detailedChipView.setTextColor(builder.textColor);
|
||||
else if (ColorUtil.isColorDark(detailedChipView.getBackgroundColor()))
|
||||
detailedChipView.setTextColor(ColorStateList.valueOf(Color.WHITE));
|
||||
else
|
||||
detailedChipView.setTextColor(ColorStateList.valueOf(Color.BLACK));
|
||||
|
||||
// delete icon color
|
||||
if (builder.deleteIconColor != null)
|
||||
detailedChipView.setDeleteIconColor(builder.deleteIconColor);
|
||||
else if (ColorUtil.isColorDark(detailedChipView.getBackgroundColor()))
|
||||
detailedChipView.setDeleteIconColor(ColorStateList.valueOf(Color.WHITE));
|
||||
else
|
||||
detailedChipView.setDeleteIconColor(ColorStateList.valueOf(Color.BLACK));
|
||||
|
||||
detailedChipView.setName(builder.name);
|
||||
detailedChipView.setInfo(builder.info);
|
||||
return detailedChipView;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'com.jakewharton.butterknife'
|
||||
|
||||
android {
|
||||
|
@ -9,9 +11,10 @@ android {
|
|||
applicationId "com.pchmn.sample.materialchipsinput"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
versionCode 9
|
||||
versionName "1.0.8"
|
||||
versionCode 10
|
||||
versionName "2.0.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
|
@ -27,14 +30,16 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation project(path: ':library')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||
implementation "androidx.appcompat:appcompat:1.0.2"
|
||||
implementation "androidx.recyclerview:recyclerview:1.0.0"
|
||||
implementation "com.google.android.material:material:1.0.0"
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation "androidx.core:core-ktx:1.0.2"
|
||||
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.7'
|
||||
implementation "androidx.recyclerview:recyclerview:1.0.0"
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation "com.google.android.material:material:1.1.0-alpha07"
|
||||
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.9'
|
||||
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
|
||||
|
||||
implementation 'com.jakewharton:butterknife:10.1.0'
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
|
Loading…
Reference in a new issue