parent
87070d52ca
commit
d230c1029d
Binary file not shown.
@ -0,0 +1,265 @@ |
||||
package xyz.fycz.myreader.ui.activity; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.content.DialogInterface; |
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
import android.os.Handler; |
||||
import android.view.Menu; |
||||
import android.view.MenuItem; |
||||
import android.view.MotionEvent; |
||||
import android.widget.LinearLayout; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
import androidx.appcompat.app.AppCompatActivity; |
||||
import androidx.appcompat.widget.Toolbar; |
||||
import androidx.documentfile.provider.DocumentFile; |
||||
import androidx.recyclerview.widget.LinearLayoutManager; |
||||
import androidx.recyclerview.widget.RecyclerView; |
||||
|
||||
import com.mcxtzhang.swipemenulib.SwipeMenuLayout; |
||||
|
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import butterknife.BindView; |
||||
import io.reactivex.Observable; |
||||
import io.reactivex.ObservableOnSubscribe; |
||||
import io.reactivex.android.schedulers.AndroidSchedulers; |
||||
import io.reactivex.annotations.NonNull; |
||||
import io.reactivex.schedulers.Schedulers; |
||||
import xyz.fycz.myreader.R; |
||||
import xyz.fycz.myreader.base.BaseActivity; |
||||
import xyz.fycz.myreader.base.observer.MyObserver; |
||||
import xyz.fycz.myreader.base.observer.MySingleObserver; |
||||
import xyz.fycz.myreader.common.APPCONST; |
||||
import xyz.fycz.myreader.greendao.entity.ReplaceRuleBean; |
||||
import xyz.fycz.myreader.model.ReplaceRuleManager; |
||||
import xyz.fycz.myreader.ui.adapter.ReplaceRuleAdapter; |
||||
import xyz.fycz.myreader.ui.dialog.DialogCreator; |
||||
import xyz.fycz.myreader.ui.dialog.MyAlertDialog; |
||||
import xyz.fycz.myreader.ui.dialog.ReplaceDialog; |
||||
import xyz.fycz.myreader.util.ToastUtils; |
||||
import xyz.fycz.myreader.util.utils.ClipBoardUtil; |
||||
import xyz.fycz.myreader.util.utils.FileUtils; |
||||
import xyz.fycz.myreader.util.utils.GsonExtensionsKt; |
||||
import xyz.fycz.myreader.widget.DividerItemDecoration; |
||||
|
||||
import static android.text.TextUtils.isEmpty; |
||||
import static xyz.fycz.myreader.util.UriFileUtil.getPath; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2021/1/19 10:02 |
||||
*/ |
||||
public class RuleActivity extends BaseActivity { |
||||
@BindView(R.id.rv_rule_list) |
||||
RecyclerView rvRuleList; |
||||
|
||||
private List<ReplaceRuleBean> mReplaceRules; |
||||
private ReplaceRuleAdapter mAdapter; |
||||
|
||||
@Override |
||||
protected int getContentId() { |
||||
return R.layout.activity_rule; |
||||
} |
||||
|
||||
@Override |
||||
protected void initData(Bundle savedInstanceState) { |
||||
super.initData(savedInstanceState); |
||||
ReplaceRuleManager.getAll().subscribe(new MySingleObserver<List<ReplaceRuleBean>>() { |
||||
@Override |
||||
public void onSuccess(@NonNull List<ReplaceRuleBean> replaceRuleBeans) { |
||||
mReplaceRules = replaceRuleBeans; |
||||
initRuleList(); |
||||
setUpBarTitle(); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Throwable e) { |
||||
ToastUtils.showError("数据加载失败\n" + e.getLocalizedMessage()); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
protected void setUpToolbar(Toolbar toolbar) { |
||||
super.setUpToolbar(toolbar); |
||||
setUpBarTitle(); |
||||
setStatusBarColor(R.color.colorPrimary, true); |
||||
} |
||||
|
||||
private void setUpBarTitle() { |
||||
getSupportActionBar().setTitle(String.format("%s(共%s个)", |
||||
getString(R.string.replace_rule), mReplaceRules == null ? 0 : mReplaceRules.size())); |
||||
} |
||||
|
||||
protected void initRuleList() { |
||||
mAdapter = new ReplaceRuleAdapter(this, (which, data) -> { |
||||
mReplaceRules.remove(data); |
||||
mAdapter.notifyItemRemoved(which); |
||||
mAdapter.removeItem2(data); |
||||
setUpBarTitle(); |
||||
}); |
||||
rvRuleList.setLayoutManager(new LinearLayoutManager(this)); |
||||
rvRuleList.setAdapter(mAdapter); |
||||
//设置分割线
|
||||
rvRuleList.addItemDecoration(new DividerItemDecoration(this)); |
||||
mAdapter.refreshItems(mReplaceRules); |
||||
} |
||||
|
||||
@SuppressLint("ClickableViewAccessibility") |
||||
@Override |
||||
protected void initClick() { |
||||
super.initClick(); |
||||
rvRuleList.setOnTouchListener((v, event) -> { |
||||
if (event.getAction() == MotionEvent.ACTION_UP) { |
||||
SwipeMenuLayout viewCache = SwipeMenuLayout.getViewCache(); |
||||
if (null != viewCache) { |
||||
viewCache.smoothClose(); |
||||
} |
||||
} |
||||
return false; |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public boolean onCreateOptionsMenu(Menu menu) { |
||||
getMenuInflater().inflate(R.menu.menu_rule, menu); |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onOptionsItemSelected(MenuItem item) { |
||||
switch (item.getItemId()) { |
||||
case R.id.action_add_rule: |
||||
ReplaceRuleBean newRuleBean = new ReplaceRuleBean(); |
||||
newRuleBean.setReplaceSummary(""); |
||||
newRuleBean.setEnable(true); |
||||
newRuleBean.setRegex(""); |
||||
newRuleBean.setIsRegex(false); |
||||
newRuleBean.setReplacement(""); |
||||
newRuleBean.setSerialNumber(0); |
||||
newRuleBean.setUseTo(""); |
||||
ReplaceDialog replaceDialog = new ReplaceDialog(this, newRuleBean |
||||
, () -> { |
||||
ToastUtils.showSuccess("内容替换规则添加成功!"); |
||||
mReplaceRules.add(newRuleBean); |
||||
mAdapter.addItem(newRuleBean); |
||||
setUpBarTitle(); |
||||
refreshUI(); |
||||
}); |
||||
replaceDialog.show(getSupportFragmentManager(), "replaceRule"); |
||||
break; |
||||
case R.id.action_import: |
||||
MyAlertDialog.build(this) |
||||
.setTitle("导入规则") |
||||
.setItems(R.array.import_rule, (dialog, which) -> { |
||||
if (which == 0) { |
||||
String text = ClipBoardUtil.paste(this); |
||||
if (!isEmpty(text)) { |
||||
importDataS(text); |
||||
} else { |
||||
ToastUtils.showError("剪切板内容为空,导入失败"); |
||||
} |
||||
} else { |
||||
ToastUtils.showInfo("请选择内容替换规则JSON文件"); |
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT); |
||||
intent.addCategory(Intent.CATEGORY_OPENABLE); |
||||
intent.setType("application/json"); |
||||
startActivityForResult(intent, APPCONST.REQUEST_IMPORT_REPLACE_RULE); |
||||
} |
||||
}).show(); |
||||
break; |
||||
case R.id.action_export: |
||||
if (mReplaceRules == null || mReplaceRules.size() == 0){ |
||||
ToastUtils.showWarring("当前没有任何规则,无法导出!"); |
||||
return true; |
||||
} |
||||
if (FileUtils.writeText(GsonExtensionsKt.getGSON().toJson(mReplaceRules), |
||||
FileUtils.getFile(APPCONST.FILE_DIR + "ReplaceRule.json"))) { |
||||
DialogCreator.createTipDialog(this, |
||||
"内容替换规则导出成功,导出位置:" + APPCONST.FILE_DIR + "ReplaceRule.json"); |
||||
} |
||||
break; |
||||
case R.id.action_reverse: |
||||
for (ReplaceRuleBean ruleBean : mReplaceRules) { |
||||
ruleBean.setEnable(!ruleBean.getEnable()); |
||||
} |
||||
ReplaceRuleManager.addDataS(mReplaceRules); |
||||
mAdapter.notifyDataSetChanged(); |
||||
refreshUI(); |
||||
break; |
||||
case R.id.action_delete: |
||||
DialogCreator.createCommonDialog(this, "删除禁用规则", |
||||
"确定要删除所有禁用规则吗?", true, |
||||
(dialog, which) -> { |
||||
List<ReplaceRuleBean> ruleBeans = new ArrayList<>(); |
||||
for (ReplaceRuleBean ruleBean : mReplaceRules) { |
||||
if (!ruleBean.getEnable()) { |
||||
ruleBeans.add(ruleBean); |
||||
} |
||||
} |
||||
ReplaceRuleManager.delDataS(ruleBeans); |
||||
mReplaceRules.removeAll(ruleBeans); |
||||
mAdapter.removeItems(ruleBeans); |
||||
ToastUtils.showSuccess("禁用规则删除成功"); |
||||
setUpBarTitle(); |
||||
refreshUI(); |
||||
}, null); |
||||
break; |
||||
} |
||||
return super.onOptionsItemSelected(item); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { |
||||
if (resultCode == RESULT_OK) { |
||||
if (requestCode == APPCONST.REQUEST_IMPORT_REPLACE_RULE) { |
||||
String path = getPath(this, data.getData()); |
||||
String json = FileUtils.readText(path); |
||||
if (!isEmpty(json)) { |
||||
importDataS(json); |
||||
} else { |
||||
ToastUtils.showError("文件读取失败"); |
||||
} |
||||
} |
||||
} |
||||
super.onActivityResult(requestCode, resultCode, data); |
||||
} |
||||
|
||||
public void importDataS(String text) { |
||||
Observable<Boolean> observable = ReplaceRuleManager.importReplaceRule(text); |
||||
if (observable != null) { |
||||
observable.subscribe(new MyObserver<Boolean>() { |
||||
@Override |
||||
public void onNext(Boolean aBoolean) { |
||||
if (aBoolean) { |
||||
mReplaceRules = ReplaceRuleManager.getAllRules(); |
||||
mAdapter.refreshItems(mReplaceRules); |
||||
setUpBarTitle(); |
||||
refreshUI(); |
||||
ToastUtils.showSuccess("内容替换规则导入成功"); |
||||
} else { |
||||
ToastUtils.showError("格式不对"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Throwable e) { |
||||
ToastUtils.showError("格式不对"); |
||||
} |
||||
}); |
||||
} else { |
||||
ToastUtils.showError("导入失败"); |
||||
} |
||||
} |
||||
|
||||
private void refreshUI() { |
||||
Intent result = new Intent(); |
||||
result.putExtra(APPCONST.RESULT_NEED_REFRESH, true); |
||||
setResult(AppCompatActivity.RESULT_OK, result); |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
package xyz.fycz.myreader.ui.adapter; |
||||
|
||||
import android.app.Activity; |
||||
|
||||
import androidx.appcompat.app.AppCompatActivity; |
||||
|
||||
import xyz.fycz.myreader.base.adapter.BaseListAdapter; |
||||
import xyz.fycz.myreader.base.adapter.IViewHolder; |
||||
import xyz.fycz.myreader.greendao.entity.ReplaceRuleBean; |
||||
import xyz.fycz.myreader.ui.adapter.holder.ReplaceRuleHolder; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2021/1/19 9:51 |
||||
*/ |
||||
public class ReplaceRuleAdapter extends BaseListAdapter<ReplaceRuleBean> { |
||||
private AppCompatActivity activity; |
||||
private OnDeleteListener onDeleteListener; |
||||
|
||||
public ReplaceRuleAdapter(AppCompatActivity activity, OnDeleteListener onDeleteListener) { |
||||
this.activity = activity; |
||||
this.onDeleteListener = onDeleteListener; |
||||
} |
||||
|
||||
@Override |
||||
protected IViewHolder<ReplaceRuleBean> createViewHolder(int viewType) { |
||||
return new ReplaceRuleHolder(activity, onDeleteListener); |
||||
} |
||||
|
||||
public void removeItem2(ReplaceRuleBean ruleBean){ |
||||
mList.remove(ruleBean); |
||||
} |
||||
|
||||
public interface OnDeleteListener{ |
||||
void success(int which, ReplaceRuleBean ruleBean); |
||||
} |
||||
} |
@ -0,0 +1,144 @@ |
||||
package xyz.fycz.myreader.ui.adapter.holder; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.ClipData; |
||||
import android.content.ClipboardManager; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.widget.Button; |
||||
import android.widget.RelativeLayout; |
||||
import android.widget.TextView; |
||||
|
||||
import androidx.appcompat.app.AppCompatActivity; |
||||
|
||||
import com.mcxtzhang.swipemenulib.SwipeMenuLayout; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import io.reactivex.Observable; |
||||
import io.reactivex.ObservableOnSubscribe; |
||||
import io.reactivex.android.schedulers.AndroidSchedulers; |
||||
import io.reactivex.annotations.NonNull; |
||||
import io.reactivex.schedulers.Schedulers; |
||||
import xyz.fycz.myreader.R; |
||||
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; |
||||
import xyz.fycz.myreader.base.observer.MyObserver; |
||||
import xyz.fycz.myreader.base.observer.MySingleObserver; |
||||
import xyz.fycz.myreader.common.APPCONST; |
||||
import xyz.fycz.myreader.greendao.entity.ReplaceRuleBean; |
||||
import xyz.fycz.myreader.model.ReplaceRuleManager; |
||||
import xyz.fycz.myreader.ui.adapter.ReplaceRuleAdapter; |
||||
import xyz.fycz.myreader.ui.dialog.ReplaceDialog; |
||||
import xyz.fycz.myreader.util.ShareUtils; |
||||
import xyz.fycz.myreader.util.ToastUtils; |
||||
import xyz.fycz.myreader.util.utils.GsonExtensionsKt; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2021/1/19 9:54 |
||||
*/ |
||||
public class ReplaceRuleHolder extends ViewHolderImpl<ReplaceRuleBean> { |
||||
private RelativeLayout rlContent; |
||||
private TextView tvRuleSummary; |
||||
private Button btBan; |
||||
private Button btShare; |
||||
private Button btDelete; |
||||
private AppCompatActivity activity; |
||||
private ReplaceRuleAdapter.OnDeleteListener onDeleteListener; |
||||
|
||||
public ReplaceRuleHolder(AppCompatActivity activity, ReplaceRuleAdapter.OnDeleteListener onDeleteListener) { |
||||
this.activity = activity; |
||||
this.onDeleteListener = onDeleteListener; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected int getItemLayoutId() { |
||||
return R.layout.item_replace_rule; |
||||
} |
||||
|
||||
@Override |
||||
public void initView() { |
||||
rlContent = findById(R.id.rl_content); |
||||
tvRuleSummary = findById(R.id.tv_rule_summary); |
||||
btBan = findById(R.id.bt_ban); |
||||
btShare = findById(R.id.bt_share); |
||||
btDelete = findById(R.id.btnDelete); |
||||
} |
||||
|
||||
@Override |
||||
public void onBind(ReplaceRuleBean data, int pos) { |
||||
banOrUse(data); |
||||
|
||||
rlContent.setOnClickListener(v -> { |
||||
ReplaceDialog replaceDialog = new ReplaceDialog(activity, data, |
||||
() -> { |
||||
banOrUse(data); |
||||
ToastUtils.showSuccess("内容替换规则修改成功!"); |
||||
refreshUI(); |
||||
}); |
||||
replaceDialog.show(activity.getSupportFragmentManager(), ""); |
||||
}); |
||||
|
||||
btBan.setOnClickListener(v -> { |
||||
((SwipeMenuLayout) getItemView()).smoothClose(); |
||||
data.setEnable(!data.getEnable()); |
||||
ReplaceRuleManager.saveData(data) |
||||
.subscribe(new MySingleObserver<Boolean>() { |
||||
@Override |
||||
public void onSuccess(@NonNull Boolean aBoolean) { |
||||
if (aBoolean) { |
||||
banOrUse(data); |
||||
refreshUI(); |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
btShare.setOnClickListener(v -> { |
||||
((SwipeMenuLayout) getItemView()).smoothClose(); |
||||
List<ReplaceRuleBean> shareRuleBean = new ArrayList<>(); |
||||
shareRuleBean.add(data); |
||||
ShareUtils.share(activity, GsonExtensionsKt.getGSON().toJson(shareRuleBean)); |
||||
}); |
||||
btDelete.setOnClickListener(v -> { |
||||
((SwipeMenuLayout) getItemView()).smoothClose(); |
||||
Observable.create((ObservableOnSubscribe<Boolean>) e -> { |
||||
ReplaceRuleManager.delData(data); |
||||
e.onNext(true); |
||||
}).subscribeOn(Schedulers.io()) |
||||
.observeOn(AndroidSchedulers.mainThread()) |
||||
.subscribe(new MyObserver<Boolean>() { |
||||
@Override |
||||
public void onNext(Boolean aBoolean) { |
||||
onDeleteListener.success(pos, data); |
||||
refreshUI(); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Throwable e) { |
||||
ToastUtils.showError("删除失败"); |
||||
} |
||||
}); |
||||
|
||||
}); |
||||
} |
||||
|
||||
private void banOrUse(ReplaceRuleBean data){ |
||||
if (data.getEnable()) { |
||||
tvRuleSummary.setTextColor(getContext().getResources().getColor(R.color.textPrimary)); |
||||
tvRuleSummary.setText(String.format("%s->%s", data.getRegex(), data.getReplacement())); |
||||
btBan.setText(getContext().getString(R.string.ban)); |
||||
} else { |
||||
tvRuleSummary.setTextColor(getContext().getResources().getColor(R.color.textSecondary)); |
||||
tvRuleSummary.setText(String.format("(禁用中)%s->%s", data.getRegex(), data.getReplacement())); |
||||
btBan.setText(R.string.enable_use); |
||||
} |
||||
} |
||||
|
||||
private void refreshUI(){ |
||||
Intent result = new Intent(); |
||||
result.putExtra(APPCONST.RESULT_NEED_REFRESH, true); |
||||
activity.setResult(AppCompatActivity.RESULT_OK, result); |
||||
} |
||||
} |
@ -0,0 +1,218 @@ |
||||
package xyz.fycz.myreader.ui.dialog; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.DialogInterface; |
||||
import android.os.Bundle; |
||||
import android.view.LayoutInflater; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.Button; |
||||
import android.widget.CheckBox; |
||||
import android.widget.EditText; |
||||
import android.widget.TextView; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
import androidx.annotation.Nullable; |
||||
import androidx.appcompat.widget.AppCompatEditText; |
||||
import androidx.fragment.app.DialogFragment; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.List; |
||||
|
||||
import xyz.fycz.myreader.R; |
||||
import xyz.fycz.myreader.base.observer.MySingleObserver; |
||||
import xyz.fycz.myreader.enums.BookSource; |
||||
import xyz.fycz.myreader.greendao.entity.Book; |
||||
import xyz.fycz.myreader.greendao.entity.ReplaceRuleBean; |
||||
import xyz.fycz.myreader.greendao.service.BookService; |
||||
import xyz.fycz.myreader.model.ReplaceRuleManager; |
||||
import xyz.fycz.myreader.util.SharedPreUtils; |
||||
import xyz.fycz.myreader.util.ToastUtils; |
||||
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2021/1/18 20:04 |
||||
*/ |
||||
public class ReplaceDialog extends DialogFragment { |
||||
private ReplaceRuleBean replaceRule; |
||||
private Activity activity; |
||||
private OnSaveReplaceRule onSaveReplaceRule; |
||||
private EditText etRuleDesc; |
||||
private EditText etRuleOld; |
||||
private EditText etRuleNew; |
||||
private EditText etRuleSource; |
||||
private EditText etRuleBook; |
||||
private CheckBox cbUseRegex; |
||||
private Button btSelectSource; |
||||
private Button btSelectBook; |
||||
private TextView tvConfirm; |
||||
private TextView tvCancel; |
||||
|
||||
public ReplaceDialog(Activity activity, ReplaceRuleBean replaceRule, OnSaveReplaceRule onSaveReplaceRule) { |
||||
this.activity = activity; |
||||
this.replaceRule = replaceRule; |
||||
this.onSaveReplaceRule = onSaveReplaceRule; |
||||
} |
||||
|
||||
@Override |
||||
public void onCreate(@Nullable Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setStyle(DialogFragment.STYLE_NORMAL, R.style.alertDialogTheme); |
||||
} |
||||
|
||||
@Nullable |
||||
@Override |
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
||||
View v = inflater.inflate(R.layout.dialog_replace, container, false); |
||||
etRuleDesc = v.findViewById(R.id.et_rule_desc); |
||||
etRuleOld = v.findViewById(R.id.et_rule_old); |
||||
etRuleNew = v.findViewById(R.id.et_rule_new); |
||||
etRuleSource = v.findViewById(R.id.et_rule_source); |
||||
etRuleBook = v.findViewById(R.id.et_rule_book); |
||||
cbUseRegex = v.findViewById(R.id.cb_use_regex); |
||||
btSelectSource = v.findViewById(R.id.bt_select_source); |
||||
btSelectBook = v.findViewById(R.id.bt_select_book); |
||||
tvCancel = v.findViewById(R.id.tv_cancel); |
||||
tvConfirm = v.findViewById(R.id.tv_confirm); |
||||
|
||||
etRuleDesc.setText(replaceRule.getReplaceSummary()); |
||||
etRuleOld.setText(replaceRule.getRegex()); |
||||
cbUseRegex.setChecked(replaceRule.getIsRegex()); |
||||
etRuleNew.setText(replaceRule.getReplacement()); |
||||
String[] useTo = replaceRule.getUseTo().split(";"); |
||||
etRuleSource.setText(useTo.length > 0 ?useTo[0] : ""); |
||||
etRuleBook.setText(useTo.length > 1 ? useTo[1] : ""); |
||||
btSelectSource.setOnClickListener(v1 -> selectSource()); |
||||
btSelectBook.setOnClickListener(v1 -> selectBook()); |
||||
|
||||
tvConfirm.setOnClickListener(v1 -> { |
||||
replaceRule.setReplaceSummary(etRuleDesc.getText().toString()); |
||||
replaceRule.setRegex(etRuleOld.getText().toString()); |
||||
replaceRule.setIsRegex(cbUseRegex.isChecked()); |
||||
replaceRule.setReplacement(etRuleNew.getText().toString()); |
||||
replaceRule.setUseTo(String.format("%s;%s", etRuleSource.getText().toString(), etRuleBook.getText().toString())); |
||||
ReplaceRuleManager.saveData(replaceRule).subscribe(new MySingleObserver<Boolean>() { |
||||
@Override |
||||
public void onSuccess(@NonNull Boolean aBoolean) { |
||||
onSaveReplaceRule.success(); |
||||
dismiss(); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Throwable e) { |
||||
ToastUtils.showError("发生错误\n" + e.getLocalizedMessage()); |
||||
} |
||||
}); |
||||
}); |
||||
tvCancel.setOnClickListener(v1 -> dismiss()); |
||||
return v; |
||||
} |
||||
|
||||
/** |
||||
* 选择书源 |
||||
*/ |
||||
private void selectSource(){ |
||||
List<String> mSources = ReadCrawlerUtil.getAllSources(); |
||||
CharSequence[] mSourcesName = new CharSequence[mSources.size()]; |
||||
HashMap<CharSequence, Boolean> mSelectSources = new LinkedHashMap<>(); |
||||
boolean[] isSelects = new boolean[mSources.size()]; |
||||
int sSourceCount = 0; |
||||
int i = 0; |
||||
|
||||
String selectSource = etRuleSource.getText().toString(); |
||||
|
||||
for (CharSequence sourceName : mSources) { |
||||
mSourcesName[i] = sourceName; |
||||
String source = BookSource.getFromName(String.valueOf(sourceName)); |
||||
boolean isSelect = selectSource.contains(source); |
||||
if (isSelect) sSourceCount++; |
||||
mSelectSources.put(mSourcesName[i], isSelect); |
||||
isSelects[i++] = isSelect; |
||||
} |
||||
|
||||
new MultiChoiceDialog().create(activity, "选择书源", |
||||
mSourcesName, isSelects, sSourceCount, (dialog, which) -> { |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (CharSequence sourceName : mSelectSources.keySet()) { |
||||
if (mSelectSources.get(sourceName)) { |
||||
sb.append(BookSource.getFromName(String.valueOf(sourceName))); |
||||
sb.append(","); |
||||
} |
||||
} |
||||
if (sb.lastIndexOf(",") >= 0) sb.deleteCharAt(sb.lastIndexOf(",")); |
||||
etRuleSource.setText(sb.toString()); |
||||
}, null, new DialogCreator.OnMultiDialogListener() { |
||||
@Override |
||||
public void onItemClick(DialogInterface dialog, int which, boolean isChecked) { |
||||
mSelectSources.put(mSourcesName[which], isChecked); |
||||
} |
||||
|
||||
@Override |
||||
public void onSelectAll(boolean isSelectAll) { |
||||
for (CharSequence sourceName : mSelectSources.keySet()) { |
||||
mSelectSources.put(sourceName, isSelectAll); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 选择书籍 |
||||
*/ |
||||
private void selectBook(){ |
||||
List<Book> mBooks = BookService.getInstance().getAllBooksNoHide(); |
||||
HashMap<CharSequence, Boolean> mSelectBooks = new LinkedHashMap<>(); |
||||
|
||||
if (mBooks == null || mBooks.size() == 0){ |
||||
ToastUtils.showWarring("当前没有任何书籍!"); |
||||
return; |
||||
} |
||||
String isSelect = etRuleBook.getText().toString(); |
||||
|
||||
CharSequence[] mBooksName = new CharSequence[mBooks.size()]; |
||||
boolean[] isSelects = new boolean[mBooks.size()]; |
||||
int sBookCount = 0; |
||||
|
||||
for (int i = 0; i < mBooks.size(); i++) { |
||||
Book book = mBooks.get(i); |
||||
mBooksName[i] = book.getName() + "-" + book.getAuthor(); |
||||
isSelects[i] = isSelect.contains(book.getName()); |
||||
if (isSelects[i]) { |
||||
mSelectBooks.put(mBooksName[i], true); |
||||
sBookCount++; |
||||
}else { |
||||
mSelectBooks.put(mBooksName[i], false); |
||||
} |
||||
} |
||||
|
||||
new MultiChoiceDialog().create(activity, "选择书籍", |
||||
mBooksName, isSelects, sBookCount, (dialog, which) -> { |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (CharSequence bookName : mSelectBooks.keySet()) { |
||||
if (mSelectBooks.get(bookName)) { |
||||
sb.append(bookName); |
||||
sb.append(","); |
||||
} |
||||
} |
||||
if (sb.lastIndexOf(",") >= 0) sb.deleteCharAt(sb.lastIndexOf(",")); |
||||
etRuleBook.setText(sb.toString()); |
||||
}, null, new DialogCreator.OnMultiDialogListener() { |
||||
@Override |
||||
public void onItemClick(DialogInterface dialog, int which, boolean isChecked) { |
||||
mSelectBooks.put(mBooksName[which], isChecked); |
||||
} |
||||
|
||||
@Override |
||||
public void onSelectAll(boolean isSelectAll) { |
||||
for (CharSequence bookName : mSelectBooks.keySet()) { |
||||
mSelectBooks.put(bookName, isSelectAll); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
public interface OnSaveReplaceRule{ |
||||
void success(); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,68 @@ |
||||
package xyz.fycz.myreader.util.utils; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2021/1/19 14:30 |
||||
*/ |
||||
|
||||
import android.content.ClipData; |
||||
import android.content.ClipboardManager; |
||||
import android.content.Context; |
||||
import android.text.TextUtils; |
||||
|
||||
import xyz.fycz.myreader.application.MyApplication; |
||||
import xyz.fycz.myreader.util.ToastUtils; |
||||
|
||||
/** |
||||
* 剪切板读写工具 |
||||
*/ |
||||
public class ClipBoardUtil { |
||||
/** |
||||
* 获取剪切板内容 |
||||
* |
||||
* @return |
||||
*/ |
||||
public static String paste(Context context) { |
||||
ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); |
||||
if (manager != null) { |
||||
if (manager.hasPrimaryClip() && manager.getPrimaryClip().getItemCount() > 0) { |
||||
CharSequence addedText = manager.getPrimaryClip().getItemAt(0).getText(); |
||||
String addedTextString = String.valueOf(addedText); |
||||
if (!TextUtils.isEmpty(addedTextString)) { |
||||
return addedTextString; |
||||
} |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
/** |
||||
* 写入剪切板 |
||||
* @param text |
||||
* @return |
||||
*/ |
||||
public static boolean write(Context context, String text){ |
||||
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); |
||||
ClipData clipData = ClipData.newPlainText(null, text); |
||||
if (clipboard != null) { |
||||
clipboard.setPrimaryClip(clipData); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 清空剪切板 |
||||
*/ |
||||
public static void clear(Context context) { |
||||
ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); |
||||
if (manager != null) { |
||||
try { |
||||
manager.setPrimaryClip(manager.getPrimaryClip()); |
||||
manager.setPrimaryClip(ClipData.newPlainText("", "")); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,642 @@ |
||||
package xyz.fycz.myreader.widget; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.Context; |
||||
import android.content.res.ColorStateList; |
||||
import android.content.res.Resources; |
||||
import android.graphics.Canvas; |
||||
import android.graphics.Color; |
||||
import android.graphics.ColorFilter; |
||||
import android.graphics.Paint; |
||||
import android.graphics.Path; |
||||
import android.graphics.PixelFormat; |
||||
import android.graphics.drawable.BitmapDrawable; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.graphics.drawable.GradientDrawable; |
||||
import android.graphics.drawable.StateListDrawable; |
||||
import android.util.Log; |
||||
import android.util.TypedValue; |
||||
import android.view.Gravity; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.view.ViewParent; |
||||
import android.widget.ImageView; |
||||
import android.widget.LinearLayout; |
||||
import android.widget.PopupWindow; |
||||
import android.widget.TextView; |
||||
|
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 仿QQ长按气泡弹窗 |
||||
* 作者:pixiaozhi |
||||
* 时间:19/05/31. |
||||
*/ |
||||
public class BubblePopupView { |
||||
|
||||
private static final boolean DEFAULT_SHOW_BOTTOM = false; |
||||
private static final boolean DEFAULT_SHOW_TOUCH_LOCATION = false; |
||||
private static final boolean DEFAULT_FOCUSABLE = true; |
||||
private static final int DEFAULT_NORMAL_TEXT_COLOR = Color.WHITE; |
||||
private static final int DEFAULT_PRESSED_TEXT_COLOR = Color.WHITE; |
||||
private static final float DEFAULT_TEXT_SIZE_DP = 14; |
||||
private static final float DEFAULT_TEXT_PADDING_LEFT_DP = 10.0f; |
||||
private static final float DEFAULT_TEXT_PADDING_TOP_DP = 5.0f; |
||||
private static final float DEFAULT_TEXT_PADDING_RIGHT_DP = 10.0f; |
||||
private static final float DEFAULT_TEXT_PADDING_BOTTOM_DP = 5.0f; |
||||
private static final int DEFAULT_NORMAL_BACKGROUND_COLOR = 0xCC000000; |
||||
private static final int DEFAULT_PRESSED_BACKGROUND_COLOR = 0xE7777777; |
||||
private static final int DEFAULT_BACKGROUND_RADIUS_DP = 8; |
||||
private static final int DEFAULT_DIVIDER_COLOR = 0x9AFFFFFF; |
||||
private static final float DEFAULT_DIVIDER_WIDTH_DP = 0.5f; |
||||
private static final float DEFAULT_DIVIDER_HEIGHT_DP = 16.0f; |
||||
private static final float DEFAULT_NAVIGATION_BAR_HEIGHT = 0f; |
||||
|
||||
private Context mContext; |
||||
private PopupWindow mPopupWindow; |
||||
private View mAnchorView; |
||||
private View mContextView; |
||||
private View mIndicatorView; |
||||
private List<String> mPopupItemList; |
||||
private PopupListListener mPopupListListener; |
||||
private int mContextPosition; |
||||
private StateListDrawable mLeftItemBackground; |
||||
private StateListDrawable mRightItemBackground; |
||||
private StateListDrawable mCornerItemBackground; |
||||
private ColorStateList mTextColorStateList; |
||||
private GradientDrawable mCornerBackground; |
||||
//指示器属性
|
||||
private int mIndicatorWidth; |
||||
private int mIndicatorHeight; |
||||
//PopupWindow属性
|
||||
private int mPopupWindowWidth; |
||||
private int mPopupWindowHeight; |
||||
//文本属性
|
||||
private int mNormalTextColor; |
||||
private int mPressedTextColor; |
||||
private float mTextSize; |
||||
private int mTextPaddingLeft; |
||||
private int mTextPaddingTop; |
||||
private int mTextPaddingRight; |
||||
private int mTextPaddingBottom; |
||||
private int mNormalBackgroundColor; |
||||
private int mPressedBackgroundColor; |
||||
private int mBackgroundCornerRadius; |
||||
//分割线属性
|
||||
private int mDividerColor; |
||||
private int mDividerWidth; |
||||
private int mDividerHeight; |
||||
//是否显示在下方
|
||||
private boolean mIsShowBottom; |
||||
//是否跟随手指显示
|
||||
private boolean mIsShowTouchLocation; |
||||
//倒转高度,当落下位置比这个值小时,气泡显示在下方
|
||||
private float mReversalHeight; |
||||
//popWindow是否聚焦,默认是
|
||||
private boolean mIsFocusable; |
||||
|
||||
public BubblePopupView(Context context) { |
||||
this.mContext = context; |
||||
this.mIsShowBottom = DEFAULT_SHOW_BOTTOM; |
||||
this.mIsShowTouchLocation = DEFAULT_SHOW_TOUCH_LOCATION; |
||||
this.mIsFocusable = DEFAULT_FOCUSABLE; |
||||
this.mReversalHeight = dp2px(DEFAULT_NAVIGATION_BAR_HEIGHT); |
||||
this.mNormalTextColor = DEFAULT_NORMAL_TEXT_COLOR; |
||||
this.mPressedTextColor = DEFAULT_PRESSED_TEXT_COLOR; |
||||
this.mTextSize = dp2px(DEFAULT_TEXT_SIZE_DP); |
||||
this.mTextPaddingLeft = dp2px(DEFAULT_TEXT_PADDING_LEFT_DP); |
||||
this.mTextPaddingTop = dp2px(DEFAULT_TEXT_PADDING_TOP_DP); |
||||
this.mTextPaddingRight = dp2px(DEFAULT_TEXT_PADDING_RIGHT_DP); |
||||
this.mTextPaddingBottom = dp2px(DEFAULT_TEXT_PADDING_BOTTOM_DP); |
||||
this.mNormalBackgroundColor = DEFAULT_NORMAL_BACKGROUND_COLOR; |
||||
this.mPressedBackgroundColor = DEFAULT_PRESSED_BACKGROUND_COLOR; |
||||
this.mBackgroundCornerRadius = dp2px(DEFAULT_BACKGROUND_RADIUS_DP); |
||||
this.mDividerColor = DEFAULT_DIVIDER_COLOR; |
||||
this.mDividerWidth = dp2px(DEFAULT_DIVIDER_WIDTH_DP); |
||||
this.mDividerHeight = dp2px(DEFAULT_DIVIDER_HEIGHT_DP); |
||||
this.mIndicatorView = getDefaultIndicatorView(mContext); |
||||
refreshBackgroundOrRadiusStateList(); |
||||
refreshTextColorStateList(mPressedTextColor, mNormalTextColor); |
||||
} |
||||
|
||||
/** |
||||
* 以气泡样式显示弹出窗口 |
||||
* |
||||
* @param anchorView 要固定弹出窗口的视图 |
||||
* @param contextPosition 上下文位置,当是列表时用于记录Position |
||||
* @param rawX 原始X坐标 |
||||
* @param rawY 原始Y坐标 |
||||
* @param popupItemList 弹出菜单列表 |
||||
* @param popupListListener 监听器 |
||||
*/ |
||||
public void showPopupListWindow(View anchorView, int contextPosition, float rawX, float rawY, |
||||
List<String> popupItemList, PopupListListener popupListListener) { |
||||
mAnchorView = anchorView; |
||||
mContextPosition = contextPosition; |
||||
mPopupItemList = popupItemList; |
||||
mPopupListListener = popupListListener; |
||||
mPopupWindow = null; |
||||
mContextView = anchorView; |
||||
if (mPopupListListener != null |
||||
&& !mPopupListListener.showPopupList(mContextView, mContextView, contextPosition)) { |
||||
return; |
||||
} |
||||
int[] location = new int[2]; |
||||
mAnchorView.getLocationOnScreen(location); |
||||
// LogUtil.e("rawX:" + rawX + ",rawY:" + rawY + ",location[0]:" + location[0] + ",location[1]" + location[1]);
|
||||
if (mIsShowTouchLocation) { |
||||
showPopupListWindow(rawX - location[0], rawY - location[1]); |
||||
} else { |
||||
Log.e("navigationBarHeight:", mReversalHeight + rawY + ",rawY:" + rawY); |
||||
if (mReversalHeight > rawY) { |
||||
mIsShowBottom = true; |
||||
showPopupListWindow(mAnchorView.getWidth() / 2f, mAnchorView.getHeight()); |
||||
} else { |
||||
mIsShowBottom = false; |
||||
showPopupListWindow(mAnchorView.getWidth() / 2f, 0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 创建布局和显示 |
||||
*/ |
||||
private void showPopupListWindow(float offsetX, float offsetY) { |
||||
if (mContext instanceof Activity && ((Activity) mContext).isFinishing()) { |
||||
return; |
||||
} |
||||
if (mPopupWindow == null) { |
||||
//创建根布局
|
||||
LinearLayout contentView = new LinearLayout(mContext); |
||||
contentView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); |
||||
contentView.setOrientation(LinearLayout.VERTICAL); |
||||
//创建list布局
|
||||
LinearLayout popupListContainer = new LinearLayout(mContext); |
||||
popupListContainer.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); |
||||
popupListContainer.setOrientation(LinearLayout.HORIZONTAL); |
||||
popupListContainer.setBackgroundDrawable(mCornerBackground); |
||||
|
||||
//创建指示器
|
||||
if (mIndicatorView != null) { |
||||
LinearLayout.LayoutParams layoutParams; |
||||
if (mIndicatorView.getLayoutParams() == null) { |
||||
layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); |
||||
} else { |
||||
layoutParams = (LinearLayout.LayoutParams) mIndicatorView.getLayoutParams(); |
||||
} |
||||
layoutParams.gravity = Gravity.CENTER; |
||||
mIndicatorView.setLayoutParams(layoutParams); |
||||
ViewParent viewParent = mIndicatorView.getParent(); |
||||
if (viewParent instanceof ViewGroup) { |
||||
((ViewGroup) viewParent).removeView(mIndicatorView); |
||||
} |
||||
|
||||
if (!mIsShowBottom) { |
||||
contentView.addView(popupListContainer); |
||||
contentView.addView(mIndicatorView); |
||||
} else { |
||||
contentView.addView(mIndicatorView); |
||||
contentView.addView(popupListContainer); |
||||
} |
||||
} |
||||
|
||||
//添加list的item
|
||||
for (int i = 0; i < mPopupItemList.size(); i++) { |
||||
TextView textView = new TextView(mContext); |
||||
textView.setTextColor(mTextColorStateList); |
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); |
||||
textView.setPadding(mTextPaddingLeft, mTextPaddingTop, mTextPaddingRight, mTextPaddingBottom); |
||||
textView.setClickable(true); |
||||
final int finalI = i; |
||||
//设置点击回调
|
||||
textView.setOnClickListener(new View.OnClickListener() { |
||||
@Override |
||||
public void onClick(View v) { |
||||
if (mPopupListListener != null) { |
||||
mPopupListListener.onPopupListClick(mContextView, mContextPosition, finalI); |
||||
hidePopupListWindow(); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
textView.setText(mPopupItemList.get(i)); |
||||
|
||||
//设置item的背景
|
||||
if (mPopupItemList.size() > 1 && i == 0) { |
||||
textView.setBackgroundDrawable(mLeftItemBackground); |
||||
} else if (mPopupItemList.size() > 1 && i == mPopupItemList.size() - 1) { |
||||
textView.setBackgroundDrawable(mRightItemBackground); |
||||
} else if (mPopupItemList.size() == 1) { |
||||
textView.setBackgroundDrawable(mCornerItemBackground); |
||||
} else { |
||||
textView.setBackgroundDrawable(getCenterItemBackground()); |
||||
} |
||||
popupListContainer.addView(textView); |
||||
//设置2个item中的分割线
|
||||
if (mPopupItemList.size() > 1 && i != mPopupItemList.size() - 1) { |
||||
View divider = new View(mContext); |
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(mDividerWidth, mDividerHeight); |
||||
layoutParams.gravity = Gravity.CENTER; |
||||
divider.setLayoutParams(layoutParams); |
||||
divider.setBackgroundColor(mDividerColor); |
||||
popupListContainer.addView(divider); |
||||
} |
||||
} |
||||
if (mPopupWindowWidth == 0) { |
||||
mPopupWindowWidth = getViewWidth(popupListContainer); |
||||
} |
||||
//获取指示器宽高
|
||||
if (mIndicatorView != null && mIndicatorWidth == 0) { |
||||
if (mIndicatorView.getLayoutParams().width > 0) { |
||||
mIndicatorWidth = mIndicatorView.getLayoutParams().width; |
||||
} else { |
||||
mIndicatorWidth = getViewWidth(mIndicatorView); |
||||
} |
||||
} |
||||
if (mIndicatorView != null && mIndicatorHeight == 0) { |
||||
if (mIndicatorView.getLayoutParams().height > 0) { |
||||
mIndicatorHeight = mIndicatorView.getLayoutParams().height; |
||||
} else { |
||||
mIndicatorHeight = getViewHeight(mIndicatorView); |
||||
} |
||||
} |
||||
if (mPopupWindowHeight == 0) { |
||||
mPopupWindowHeight = getViewHeight(popupListContainer) + mIndicatorHeight; |
||||
} |
||||
mPopupWindow = new PopupWindow(contentView, mPopupWindowWidth, mPopupWindowHeight, true); |
||||
mPopupWindow.setTouchable(true); |
||||
mPopupWindow.setFocusable(mIsFocusable); |
||||
mPopupWindow.setBackgroundDrawable(new BitmapDrawable()); |
||||
} |
||||
int[] location = new int[2]; |
||||
mAnchorView.getLocationOnScreen(location); |
||||
if (mIndicatorView != null) { |
||||
float leftTranslationLimit = mIndicatorWidth / 2f + mBackgroundCornerRadius - mPopupWindowWidth / 2f; |
||||
float rightTranslationLimit = mPopupWindowWidth / 2f - mIndicatorWidth / 2f - mBackgroundCornerRadius; |
||||
//获取最大绝对宽度,单位是px
|
||||
float maxWidth = mContext.getResources().getDisplayMetrics().widthPixels; |
||||
//通过setTranslationX改变view的位置,是不改变view的LayoutParams的,也即不改变getLeft等view的信息
|
||||
if (location[0] + offsetX < mPopupWindowWidth / 2f) { |
||||
mIndicatorView.setTranslationX(Math.max(location[0] + offsetX - mPopupWindowWidth / 2f, leftTranslationLimit)); |
||||
} else if (location[0] + offsetX + mPopupWindowWidth / 2f > maxWidth) { |
||||
mIndicatorView.setTranslationX(Math.min(location[0] + offsetX + mPopupWindowWidth / 2f - maxWidth, rightTranslationLimit)); |
||||
} else { |
||||
mIndicatorView.setTranslationX(0); |
||||
} |
||||
} |
||||
if (!mPopupWindow.isShowing()) { |
||||
int x = (int) (location[0] + offsetX - mPopupWindowWidth / 2f + 0.5f); |
||||
int y = mIsShowBottom ? (int) (location[1] + offsetY + 0.5f) : (int) (location[1] + offsetY - mPopupWindowHeight + 0.5f); |
||||
mPopupWindow.showAtLocation(mAnchorView, Gravity.NO_GRAVITY, x, y); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 刷新背景或附加状态列表 |
||||
*/ |
||||
private void refreshBackgroundOrRadiusStateList() { |
||||
// left
|
||||
GradientDrawable leftItemPressedDrawable = new GradientDrawable(); |
||||
leftItemPressedDrawable.setColor(mPressedBackgroundColor); |
||||
leftItemPressedDrawable.setCornerRadii(new float[]{ |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius, |
||||
0, 0, |
||||
0, 0, |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius}); |
||||
GradientDrawable leftItemNormalDrawable = new GradientDrawable(); |
||||
leftItemNormalDrawable.setColor(Color.TRANSPARENT); |
||||
leftItemNormalDrawable.setCornerRadii(new float[]{ |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius, |
||||
0, 0, |
||||
0, 0, |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius}); |
||||
mLeftItemBackground = new StateListDrawable(); |
||||
mLeftItemBackground.addState(new int[]{android.R.attr.state_pressed}, leftItemPressedDrawable); |
||||
mLeftItemBackground.addState(new int[]{}, leftItemNormalDrawable); |
||||
// right
|
||||
GradientDrawable rightItemPressedDrawable = new GradientDrawable(); |
||||
rightItemPressedDrawable.setColor(mPressedBackgroundColor); |
||||
rightItemPressedDrawable.setCornerRadii(new float[]{ |
||||
0, 0, |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius, |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius, |
||||
0, 0}); |
||||
GradientDrawable rightItemNormalDrawable = new GradientDrawable(); |
||||
rightItemNormalDrawable.setColor(Color.TRANSPARENT); |
||||
rightItemNormalDrawable.setCornerRadii(new float[]{ |
||||
0, 0, |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius, |
||||
mBackgroundCornerRadius, mBackgroundCornerRadius, |
||||
0, 0}); |
||||
mRightItemBackground = new StateListDrawable(); |
||||
mRightItemBackground.addState(new int[]{android.R.attr.state_pressed}, rightItemPressedDrawable); |
||||
mRightItemBackground.addState(new int[]{}, rightItemNormalDrawable); |
||||
// corner
|
||||
GradientDrawable cornerItemPressedDrawable = new GradientDrawable(); |
||||
cornerItemPressedDrawable.setColor(mPressedBackgroundColor); |
||||
cornerItemPressedDrawable.setCornerRadius(mBackgroundCornerRadius); |
||||
GradientDrawable cornerItemNormalDrawable = new GradientDrawable(); |
||||
cornerItemNormalDrawable.setColor(Color.TRANSPARENT); |
||||
cornerItemNormalDrawable.setCornerRadius(mBackgroundCornerRadius); |
||||
mCornerItemBackground = new StateListDrawable(); |
||||
mCornerItemBackground.addState(new int[]{android.R.attr.state_pressed}, cornerItemPressedDrawable); |
||||
mCornerItemBackground.addState(new int[]{}, cornerItemNormalDrawable); |
||||
mCornerBackground = new GradientDrawable(); |
||||
mCornerBackground.setColor(mNormalBackgroundColor); |
||||
mCornerBackground.setCornerRadius(mBackgroundCornerRadius); |
||||
} |
||||
|
||||
/** |
||||
* 获取中心item背景 |
||||
*/ |
||||
private StateListDrawable getCenterItemBackground() { |
||||
StateListDrawable centerItemBackground = new StateListDrawable(); |
||||
GradientDrawable centerItemPressedDrawable = new GradientDrawable(); |
||||
centerItemPressedDrawable.setColor(mPressedBackgroundColor); |
||||
GradientDrawable centerItemNormalDrawable = new GradientDrawable(); |
||||
centerItemNormalDrawable.setColor(Color.TRANSPARENT); |
||||
centerItemBackground.addState(new int[]{android.R.attr.state_pressed}, centerItemPressedDrawable); |
||||
centerItemBackground.addState(new int[]{}, centerItemNormalDrawable); |
||||
return centerItemBackground; |
||||
} |
||||
|
||||
/** |
||||
* 刷新文本颜色状态列表 |
||||
* |
||||
* @param pressedTextColor 按下文本颜色 |
||||
* @param normalTextColor 正常状态下文本颜色 |
||||
*/ |
||||
private void refreshTextColorStateList(int pressedTextColor, int normalTextColor) { |
||||
int[][] states = new int[2][]; |
||||
states[0] = new int[]{android.R.attr.state_pressed}; |
||||
states[1] = new int[]{}; |
||||
int[] colors = new int[]{pressedTextColor, normalTextColor}; |
||||
mTextColorStateList = new ColorStateList(states, colors); |
||||
} |
||||
|
||||
public void hidePopupListWindow() { |
||||
if (mContext instanceof Activity && ((Activity) mContext).isFinishing()) { |
||||
return; |
||||
} |
||||
if (mPopupWindow != null && mPopupWindow.isShowing()) { |
||||
mPopupWindow.dismiss(); |
||||
} |
||||
} |
||||
|
||||
public View getIndicatorView() { |
||||
return mIndicatorView; |
||||
} |
||||
|
||||
public View getDefaultIndicatorView(Context context) { |
||||
return getTriangleIndicatorView(context, dp2px(16), dp2px(8), DEFAULT_NORMAL_BACKGROUND_COLOR); |
||||
} |
||||
|
||||
public View getTriangleIndicatorView(Context context, final float widthPixel, final float heightPixel, |
||||
final int color) { |
||||
ImageView indicator = new ImageView(context); |
||||
Drawable drawable = new Drawable() { |
||||
@Override |
||||
public void draw(Canvas canvas) { |
||||
Path path = new Path(); |
||||
Paint paint = new Paint(); |
||||
paint.setColor(color); |
||||
paint.setStyle(Paint.Style.FILL); |
||||
if (!mIsShowBottom) { |
||||
//这里画的倒三角
|
||||
path.moveTo(0f, 0f); |
||||
path.lineTo(widthPixel, 0f); |
||||
path.lineTo(widthPixel / 2, heightPixel); |
||||
//将图像封闭,这里path.close()等同于 path.moveTo(widthPixel / 2, heightPixel);path.lineTo(widthPixel, 0);
|
||||
path.close(); |
||||
} else { |
||||
//正三角
|
||||
path.moveTo(0f, heightPixel); |
||||
path.lineTo(widthPixel, heightPixel); |
||||
path.lineTo(widthPixel / 2, 0); |
||||
path.close(); |
||||
} |
||||
canvas.drawPath(path, paint); |
||||
} |
||||
|
||||
@Override |
||||
public void setAlpha(int alpha) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void setColorFilter(ColorFilter colorFilter) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public int getOpacity() { |
||||
return PixelFormat.TRANSLUCENT; |
||||
} |
||||
|
||||
@Override |
||||
public int getIntrinsicWidth() { |
||||
return (int) widthPixel; |
||||
} |
||||
|
||||
@Override |
||||
public int getIntrinsicHeight() { |
||||
return (int) heightPixel; |
||||
} |
||||
}; |
||||
indicator.setImageDrawable(drawable); |
||||
return indicator; |
||||
} |
||||
|
||||
public void setIndicatorView(View indicatorView) { |
||||
this.mIndicatorView = indicatorView; |
||||
} |
||||
|
||||
public void setIndicatorSize(int widthPixel, int heightPixel) { |
||||
this.mIndicatorWidth = widthPixel; |
||||
this.mIndicatorHeight = heightPixel; |
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(mIndicatorWidth, mIndicatorHeight); |
||||
layoutParams.gravity = Gravity.CENTER; |
||||
if (mIndicatorView != null) { |
||||
mIndicatorView.setLayoutParams(layoutParams); |
||||
} |
||||
} |
||||
|
||||
public int getNormalTextColor() { |
||||
return mNormalTextColor; |
||||
} |
||||
|
||||
public void setNormalTextColor(int normalTextColor) { |
||||
this.mNormalTextColor = normalTextColor; |
||||
refreshTextColorStateList(mPressedTextColor, mNormalTextColor); |
||||
} |
||||
|
||||
public int getPressedTextColor() { |
||||
return mPressedTextColor; |
||||
} |
||||
|
||||
public void setPressedTextColor(int pressedTextColor) { |
||||
this.mPressedTextColor = pressedTextColor; |
||||
refreshTextColorStateList(mPressedTextColor, mNormalTextColor); |
||||
} |
||||
|
||||
public float getTextSize() { |
||||
return mTextSize; |
||||
} |
||||
|
||||
public void setTextSize(float textSizePixel) { |
||||
this.mTextSize = textSizePixel; |
||||
} |
||||
|
||||
public int getTextPaddingLeft() { |
||||
return mTextPaddingLeft; |
||||
} |
||||
|
||||
public void setTextPaddingLeft(int textPaddingLeft) { |
||||
this.mTextPaddingLeft = textPaddingLeft; |
||||
} |
||||
|
||||
public int getTextPaddingTop() { |
||||
return mTextPaddingTop; |
||||
} |
||||
|
||||
public void setTextPaddingTop(int textPaddingTop) { |
||||
this.mTextPaddingTop = textPaddingTop; |
||||
} |
||||
|
||||
public int getTextPaddingRight() { |
||||
return mTextPaddingRight; |
||||
} |
||||
|
||||
public void setTextPaddingRight(int textPaddingRight) { |
||||
this.mTextPaddingRight = textPaddingRight; |
||||
} |
||||
|
||||
public int getTextPaddingBottom() { |
||||
return mTextPaddingBottom; |
||||
} |
||||
|
||||
public void setTextPaddingBottom(int textPaddingBottom) { |
||||
this.mTextPaddingBottom = textPaddingBottom; |
||||
} |
||||
|
||||
public void setTextPadding(int left, int top, int right, int bottom) { |
||||
this.mTextPaddingLeft = left; |
||||
this.mTextPaddingTop = top; |
||||
this.mTextPaddingRight = right; |
||||
this.mTextPaddingBottom = bottom; |
||||
} |
||||
|
||||
public int getNormalBackgroundColor() { |
||||
return mNormalBackgroundColor; |
||||
} |
||||
|
||||
public void setNormalBackgroundColor(int normalBackgroundColor) { |
||||
this.mNormalBackgroundColor = normalBackgroundColor; |
||||
refreshBackgroundOrRadiusStateList(); |
||||
} |
||||
|
||||
public int getPressedBackgroundColor() { |
||||
return mPressedBackgroundColor; |
||||
} |
||||
|
||||
public void setPressedBackgroundColor(int pressedBackgroundColor) { |
||||
this.mPressedBackgroundColor = pressedBackgroundColor; |
||||
refreshBackgroundOrRadiusStateList(); |
||||
} |
||||
|
||||
public void setShowBottom(boolean isShowBottom) { |
||||
this.mIsShowBottom = isShowBottom; |
||||
} |
||||
|
||||
public void setShowTouchLocation(boolean showTouchLocation) { |
||||
mIsShowTouchLocation = showTouchLocation; |
||||
} |
||||
|
||||
public void setFocusable(boolean mIsFocusable) { |
||||
this.mIsFocusable = mIsFocusable; |
||||
} |
||||
|
||||
public int getBackgroundCornerRadius() { |
||||
return mBackgroundCornerRadius; |
||||
} |
||||
|
||||
public void setBackgroundCornerRadius(int backgroundCornerRadiusPixel) { |
||||
this.mBackgroundCornerRadius = backgroundCornerRadiusPixel; |
||||
refreshBackgroundOrRadiusStateList(); |
||||
} |
||||
|
||||
public int getDividerColor() { |
||||
return mDividerColor; |
||||
} |
||||
|
||||
public void setDividerColor(int dividerColor) { |
||||
this.mDividerColor = dividerColor; |
||||
} |
||||
|
||||
public int getDividerWidth() { |
||||
return mDividerWidth; |
||||
} |
||||
|
||||
public void setDividerWidth(int dividerWidthPixel) { |
||||
this.mDividerWidth = dividerWidthPixel; |
||||
} |
||||
|
||||
public int getDividerHeight() { |
||||
return mDividerHeight; |
||||
} |
||||
|
||||
public void setDividerHeight(int dividerHeightPixel) { |
||||
this.mDividerHeight = dividerHeightPixel; |
||||
} |
||||
|
||||
public void setmReversalHeight(float mReversalHeight) { |
||||
this.mReversalHeight = mReversalHeight; |
||||
} |
||||
|
||||
public Resources getResources() { |
||||
if (mContext == null) { |
||||
return Resources.getSystem(); |
||||
} else { |
||||
return mContext.getResources(); |
||||
} |
||||
} |
||||
|
||||
private int getViewWidth(View view) { |
||||
// 1、UNSPECIFIED,不限定。意思就是,子View想要多大,我就可以给你多大,你放心大胆的measure吧,不用管其他的。也不用管我传递给你的尺寸值。(其实Android高版本中推荐,只要是这个模式,尺寸设置为0)
|
||||
//
|
||||
// 2、EXACTLY,精确的。意思就是,根据我当前的状况,结合你指定的尺寸参数来考虑,你就应该是这个尺寸,具体大小在MeasureSpec的尺寸属性中,自己去查看吧,你也不要管你的content有多大了,就用这个尺寸吧。
|
||||
//
|
||||
// 3、AT_MOST,最多的。意思就是,根据我当前的情况,结合你指定的尺寸参数来考虑,在不超过我给你限定的尺寸的前提下,你测量一个恰好能包裹你内容的尺寸就可以了。
|
||||
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); |
||||
return view.getMeasuredWidth(); |
||||
} |
||||
|
||||
private int getViewHeight(View view) { |
||||
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); |
||||
return view.getMeasuredHeight(); |
||||
} |
||||
|
||||
public int dp2px(float value) { |
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, |
||||
value, getResources().getDisplayMetrics()); |
||||
} |
||||
|
||||
public int sp2px(float value) { |
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, |
||||
value, getResources().getDisplayMetrics()); |
||||
} |
||||
|
||||
/** |
||||
* 回调监听器 |
||||
*/ |
||||
public interface PopupListListener { |
||||
boolean showPopupList(View adapterView, View contextView, int contextPosition); |
||||
|
||||
void onPopupListClick(View contextView, int contextPosition, int position); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="24" |
||||
android:viewportHeight="24"> |
||||
|
||||
<path |
||||
android:fillColor="#595757" |
||||
android:pathData="M12,4h8v8c0,4.418-3.582,8-8,8s-8-3.582-8-8S7.582,4,12,4z" /> |
||||
</vector> |
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="24" |
||||
android:viewportHeight="24"> |
||||
|
||||
<path |
||||
android:fillColor="#595757" |
||||
android:pathData="M12,4.208H4v8c0,4.418,3.582,8,8,8s8-3.582,8-8S16.418,4.208,12,4.208z" /> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:pathData="M733.86,791.95c0,26.57 -21.63,48.2 -48.2,48.2L338.35,840.15c-26.57,0 -48.2,-21.63 -48.2,-48.2L290.14,280.26h443.71v511.69zM386.55,193.74c0,-5.56 4.33,-9.89 9.89,-9.89h231.74c5.56,0 9.89,4.33 9.89,9.89v29.05L386.55,222.78L386.55,193.74zM878.46,222.78L695.54,222.78L695.54,193.74c0,-37.08 -30.28,-67.36 -67.36,-67.36h-231.74c-37.08,0 -67.36,30.28 -67.36,67.36v29.05L145.54,222.78C129.47,222.78 116.49,235.76 116.49,251.83s12.98,29.05 29.05,29.05h86.52v511.07c0,58.71 47.58,106.29 106.29,106.29h347.31c58.71,0 106.29,-47.58 106.29,-106.29L791.95,280.26h86.52c16.07,0 29.05,-12.98 29.05,-29.05s-12.98,-28.43 -29.05,-28.43zM512,753.01c16.07,0 29.05,-12.98 29.05,-29.05v-308.99c0,-16.07 -12.98,-29.05 -29.05,-29.05s-29.05,12.98 -29.05,29.05v308.99c0,16.07 12.98,29.05 29.05,29.05m-135.34,0c16.07,0 29.05,-12.98 29.05,-29.05v-308.99c0,-16.07 -12.98,-29.05 -29.05,-29.05s-29.05,12.98 -29.05,29.05v308.99c0.62,16.07 13.6,29.05 29.05,29.05m270.68,0c16.07,0 29.05,-12.98 29.05,-29.05v-308.99c0,-16.07 -12.98,-29.05 -29.05,-29.05s-29.05,12.98 -29.05,29.05v308.99c0,16.07 12.98,29.05 29.05,29.05" |
||||
android:fillColor="#FFFFFF"/> |
||||
</vector> |
@ -0,0 +1,15 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:pathData="M778.75,845.31H245.25c-53.76,0 -97.28,-43.52 -97.28,-97.28V275.46c0,-53.76 43.52,-97.28 97.28,-97.28h131.07c17.92,0 35.33,8.19 46.59,22.02l57.34,69.12h303.62c50.69,0 91.65,40.96 91.65,91.65v387.07c0.51,53.76 -43.52,97.28 -96.77,97.28zM245.25,239.1c-19.97,0 -36.35,16.38 -36.35,36.35v472.58c0,19.97 16.38,36.35 36.35,36.35h533.5c19.97,0 36.35,-16.38 36.35,-36.35V360.96c0,-16.9 -13.82,-30.72 -31.23,-30.72H480.77c-17.92,0 -35.33,-8.19 -46.59,-22.02L376.83,239.1H245.25z" |
||||
android:fillColor="#FFFFFF"/> |
||||
<path |
||||
android:pathData="M614.4,584.4c-8.7,0 -17.4,-3.4 -24.2,-10L512,496.2l-78.2,78.2c-13.3,13.4 -35,13.4 -48.2,0 -13.4,-13.4 -13.4,-35 0,-48.2L488,423.8c13.3,-13.4 35,-13.4 48.2,0l102.4,102.4c13.4,13.4 13.4,35 0,48.2 -6.8,6.8 -15.5,10 -24.2,10zM614.4,584.4" |
||||
android:fillColor="#FFFFFF"/> |
||||
<path |
||||
android:pathData="M512.51,424.45c16.9,0 30.21,13.82 30.21,30.21v211.97c0,16.9 -13.82,30.21 -30.21,30.21 -16.9,0 -30.21,-13.82 -30.21,-30.21V454.66c0,-16.9 13.82,-30.21 30.21,-30.21z" |
||||
android:fillColor="#FFFFFF"/> |
||||
</vector> |
@ -0,0 +1,15 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:pathData="M778.75,845.31H245.25c-53.76,0 -97.28,-43.52 -97.28,-97.28V275.46c0,-53.76 43.52,-97.28 97.28,-97.28h131.07c17.92,0 35.33,8.19 46.59,22.02l57.34,69.12h303.62c50.69,0 91.65,40.96 91.65,91.65v387.07c0.51,53.76 -43.52,97.28 -96.77,97.28zM245.25,239.1c-19.97,0 -36.35,16.38 -36.35,36.35v472.58c0,19.97 16.38,36.35 36.35,36.35h533.5c19.97,0 36.35,-16.38 36.35,-36.35V360.96c0,-16.9 -13.82,-30.72 -31.23,-30.72H480.77c-17.92,0 -35.33,-8.19 -46.59,-22.02L376.83,239.1H245.25z" |
||||
android:fillColor="#FFFFFF"/> |
||||
<path |
||||
android:pathData="M421.89,545.79c7.68,0 15.36,3.07 21.5,8.7l69.63,69.63 69.63,-69.63c11.78,-11.78 31.23,-11.78 43.01,0 11.78,11.78 11.78,31.23 0,43.01l-91.14,91.14c-11.78,11.78 -31.23,11.78 -43.01,0l-91.14,-91.14c-11.78,-11.78 -11.78,-31.23 0,-43.01 5.63,-6.14 13.82,-8.7 21.5,-8.7z" |
||||
android:fillColor="#FFFFFF"/> |
||||
<path |
||||
android:pathData="M512.51,424.45c16.9,0 30.21,13.82 30.21,30.21v211.97c0,16.9 -13.82,30.21 -30.21,30.21 -16.9,0 -30.21,-13.82 -30.21,-30.21V454.66c0,-16.9 13.82,-30.21 30.21,-30.21z" |
||||
android:fillColor="#FFFFFF"/> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:pathData="M410.11,449.31h-55.92l-39.94,-107.18L151.1,342.13l-37.55,107.18h-55.98l149.22,-391.68h54.1L410.17,449.31zM298.61,297.81l-59.16,-162.76a182.39,182.39 0,0 1,-6.14 -27.31L232.11,107.75a146.66,146.66 0,0 1,-6.26 27.31L167.03,297.81h131.47zM662.93,967.11v-395.95h137.56c41.07,0 73.96,8.31 98.42,24.92 24.63,16.67 36.92,38.68 36.92,66.1 0,21.79 -7.34,41.02 -21.96,57.8 -14.62,16.73 -34.7,28.44 -60.3,35.56v1.02c31.86,3.02 57.29,13.2 76.34,30.55 19.06,17.35 28.5,39.25 28.5,65.82 0,34.13 -14.45,61.67 -43.35,82.72 -28.79,20.99 -65.82,31.46 -110.93,31.46h-141.2zM723.46,615.88v124.02h55.01c29.18,0 52.17,-6.09 68.72,-18.03 16.33,-11.32 25.71,-30.15 25.03,-49.95 0,-37.32 -29.41,-55.92 -88.23,-55.92h-60.53v-0.11zM723.46,784.38v138.01h72.48c31.57,0 56.04,-6.14 73.39,-18.55a59.73,59.73 0,0 0,25.71 -51.48c0,-45.34 -36.41,-67.98 -109.11,-67.98h-62.46zM440.15,864.2l6.49,-38.17a353.62,353.62 0,0 1,-265.39 -311.98h64.68a291.9,291.9 0,0 0,212.31 248.55l9.73,-54.39 121.06,102.29 -148.88,53.7z" |
||||
android:fillColor="#FFFFFF"/> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:pathData="M298.24,469.33L128,640l170.24,170.67v-128h299.09v-85.33H298.24v-128zM896,384L725.76,213.33v128H426.67v85.33H725.76v128L896,384z" |
||||
android:fillColor="#FFFFFF"/> |
||||
</vector> |
@ -0,0 +1,12 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:pathData="M618.92,469.52c-22.9,23.46 -22.9,61.5 0,84.97l116.95,128.1c22.91,23.46 60.05,23.46 82.96,0 22.9,-23.46 22.9,-61.5 0,-84.97l-75.57,-85.62 75.57,-85.62c22.9,-23.47 22.9,-61.51 0,-84.97 -22.91,-23.47 -60.05,-23.47 -82.96,0L618.92,469.52v-0z" |
||||
android:fillColor="#FFFFFF"/> |
||||
<path |
||||
android:pathData="M705.45,857.03L329.51,512l375.94,-345.03c22.91,-23.47 22.91,-61.51 0,-84.97 -22.9,-23.47 -60.04,-23.47 -82.96,0L205.17,469.52c-22.91,23.46 -22.91,61.5 0,84.97L622.49,942c22.91,23.46 60.05,23.46 82.95,0 22.91,-23.46 22.91,-61.5 0,-84.97z" |
||||
android:fillColor="#FFFFFF"/> |
||||
</vector> |
@ -0,0 +1,16 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout |
||||
xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical"> |
||||
|
||||
<include layout="@layout/toolbar"/> |
||||
|
||||
<androidx.recyclerview.widget.RecyclerView |
||||
android:id="@+id/rv_rule_list" |
||||
android:background="@color/colorForeground" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent"/> |
||||
|
||||
</LinearLayout> |
@ -0,0 +1,221 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:background="@color/colorForeground" |
||||
android:orientation="vertical"> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
android:padding="5dp"> |
||||
|
||||
|
||||
<TextView |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:gravity="center" |
||||
android:paddingTop="10dp" |
||||
android:text="@string/content_replace" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="@dimen/text_medium_size" /> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal" |
||||
android:padding="5dp"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/summary" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="@dimen/text_normal_size" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText |
||||
android:id="@+id/et_rule_desc" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:hint="@string/summary_tip" |
||||
android:maxLines="3" |
||||
android:paddingStart="10dp" |
||||
android:paddingEnd="10dp" |
||||
android:textSize="@dimen/text_small_size" /> |
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal" |
||||
android:padding="5dp"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/replace_rule_old" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="@dimen/text_normal_size" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText |
||||
android:id="@+id/et_rule_old" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:hint="@string/replace_rule_old_tip" |
||||
android:maxLines="3" |
||||
android:paddingStart="10dp" |
||||
android:paddingEnd="10dp" |
||||
android:textSize="@dimen/text_small_size" /> |
||||
</LinearLayout> |
||||
|
||||
<CheckBox |
||||
android:id="@+id/cb_use_regex" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="20dp" |
||||
android:text="@string/replace_use_regex" |
||||
android:textColor="@color/textPrimary" |
||||
android:theme="@style/MyCheckBox" /> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal" |
||||
android:padding="5dp"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/replace_rule_new" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="@dimen/text_normal_size" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText |
||||
android:id="@+id/et_rule_new" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:hint="@string/replace_rule_new_tip" |
||||
android:maxLines="3" |
||||
android:paddingStart="10dp" |
||||
android:paddingEnd="10dp" |
||||
android:textSize="@dimen/text_small_size" /> |
||||
</LinearLayout> |
||||
|
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal" |
||||
android:padding="5dp"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/use_to_source" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="@dimen/text_normal_size" /> |
||||
|
||||
<RelativeLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText |
||||
android:id="@+id/et_rule_source" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_alignParentStart="true" |
||||
android:layout_centerVertical="true" |
||||
android:hint="@string/use_to_source_tip" |
||||
android:maxLines="3" |
||||
android:paddingStart="10dp" |
||||
android:paddingEnd="10dp" |
||||
android:textSize="@dimen/text_small_size" /> |
||||
|
||||
<Button |
||||
android:id="@+id/bt_select_source" |
||||
android:layout_width="48dp" |
||||
android:layout_height="35dp" |
||||
android:layout_alignParentEnd="true" |
||||
android:text="@string/select" |
||||
android:textSize="@dimen/text_default_size" /> |
||||
</RelativeLayout> |
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal" |
||||
android:padding="5dp"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/use_to_book" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="@dimen/text_normal_size" /> |
||||
|
||||
<RelativeLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText |
||||
android:id="@+id/et_rule_book" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_alignParentStart="true" |
||||
android:layout_centerVertical="true" |
||||
android:hint="@string/use_to_book_tip" |
||||
android:maxLines="3" |
||||
android:paddingStart="10dp" |
||||
android:paddingEnd="10dp" |
||||
android:textSize="@dimen/text_small_size" /> |
||||
|
||||
<Button |
||||
android:id="@+id/bt_select_book" |
||||
android:layout_width="48dp" |
||||
android:layout_height="35dp" |
||||
android:layout_alignParentEnd="true" |
||||
android:text="@string/select" |
||||
android:textSize="@dimen/text_default_size" /> |
||||
</RelativeLayout> |
||||
</LinearLayout> |
||||
</LinearLayout> |
||||
|
||||
<View |
||||
android:layout_width="match_parent" |
||||
android:layout_height="0.5dp" |
||||
android:background="@color/colorBackground" /> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal"> |
||||
|
||||
<TextView |
||||
android:id="@+id/tv_cancel" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="50dp" |
||||
android:layout_weight="1" |
||||
android:background="@drawable/selector_common_bg" |
||||
android:gravity="center" |
||||
android:text="@string/cancel" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="16sp" /> |
||||
|
||||
<View |
||||
android:layout_width="0.5dp" |
||||
android:layout_height="match_parent" |
||||
android:background="@color/colorBackground" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/tv_confirm" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="50dp" |
||||
android:layout_weight="1" |
||||
android:background="@drawable/selector_common_bg" |
||||
android:gravity="center" |
||||
android:text="@string/confirm" |
||||
android:textColor="@color/textPrimary" |
||||
android:textSize="16sp" /> |
||||
</LinearLayout> |
||||
</LinearLayout> |
@ -0,0 +1,79 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<com.mcxtzhang.swipemenulib.SwipeMenuLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="50dp" |
||||
android:clickable="true" |
||||
android:paddingBottom="1dp" |
||||
app:ios="false" |
||||
app:leftSwipe="true" |
||||
app:swipeEnable="true" |
||||
android:focusable="true"> |
||||
|
||||
<RelativeLayout |
||||
android:id="@+id/rl_content" |
||||
android:paddingStart="10dp" |
||||
android:paddingEnd="10dp" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:background="?android:attr/selectableItemBackground"> |
||||
|
||||
<TextView |
||||
android:id="@+id/tv_rule_summary" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:layout_toStartOf="@+id/iv_swipe_left" |
||||
android:textColor="@color/textPrimary" |
||||
android:maxLines="1" |
||||
android:ellipsize="end" |
||||
android:layout_alignParentStart="true" |
||||
android:gravity="center_vertical" |
||||
android:text="@string/summary" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/iv_swipe_left" |
||||
android:layout_width="13dp" |
||||
android:layout_height="13dp" |
||||
android:layout_centerVertical="true" |
||||
android:layout_alignParentEnd="true" |
||||
app:tint="@color/textAssist" |
||||
app:srcCompat="@drawable/ic_swipe_left"/> |
||||
|
||||
</RelativeLayout> |
||||
|
||||
|
||||
|
||||
<!-- 以下都是侧滑菜单的内容依序排列 --> |
||||
<!--<Button |
||||
android:id="@+id/bt_top" |
||||
android:layout_width="65dp" |
||||
android:layout_height="match_parent" |
||||
android:background="@color/md_purple_500" |
||||
android:text="@string/top" |
||||
android:textColor="@android:color/white"/>--> |
||||
<Button |
||||
android:id="@+id/bt_ban" |
||||
android:layout_width="65dp" |
||||
android:layout_height="match_parent" |
||||
android:background="@color/md_blue_500" |
||||
android:text="@string/ban" |
||||
android:textColor="@android:color/white"/> |
||||
<Button |
||||
android:id="@+id/bt_share" |
||||
android:layout_width="65dp" |
||||
android:layout_height="match_parent" |
||||
android:background="@color/md_yellow_800" |
||||
android:clickable="true" |
||||
android:text="@string/share" |
||||
android:textColor="@android:color/white" |
||||
android:focusable="true" /> |
||||
|
||||
<Button |
||||
android:id="@+id/btnDelete" |
||||
android:layout_width="65dp" |
||||
android:layout_height="match_parent" |
||||
android:background="@color/md_red_500" |
||||
android:text="@string/delete" |
||||
android:textColor="@android:color/white"/> |
||||
|
||||
</com.mcxtzhang.swipemenulib.SwipeMenuLayout> |
@ -0,0 +1,29 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
tools:showIn="bottom_navigation_view"> |
||||
|
||||
<item |
||||
android:id="@+id/action_add_rule" |
||||
android:icon="@drawable/ic_add" |
||||
android:title="@string/add_rule"/> |
||||
<item |
||||
android:id="@+id/action_import" |
||||
android:icon="@drawable/ic_import" |
||||
android:title="@string/import_rule"/> |
||||
|
||||
<item |
||||
android:id="@+id/action_export" |
||||
android:icon="@drawable/ic_export" |
||||
android:title="@string/export_all"/> |
||||
<item |
||||
android:id="@+id/action_reverse" |
||||
android:icon="@drawable/ic_reverse" |
||||
android:title="@string/reverse_rule"/> |
||||
|
||||
<item |
||||
android:id="@+id/action_delete" |
||||
android:icon="@drawable/ic_delete" |
||||
android:title="@string/delete_ban_rule"/> |
||||
|
||||
</menu> |
@ -1,2 +1,2 @@ |
||||
#Sat Jan 09 20:56:54 CST 2021 |
||||
VERSION_CODE=178 |
||||
#Tue Jan 19 16:58:48 CST 2021 |
||||
VERSION_CODE=179 |
||||
|
Loading…
Reference in new issue