parent
64abf589b1
commit
39160c8ff0
@ -1,74 +0,0 @@ |
|||||||
package xyz.fycz.myreader.entity; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author fengyue |
|
||||||
* @date 2022/2/17 18:56 |
|
||||||
*/ |
|
||||||
public class AdBean { |
|
||||||
//是否云控
|
|
||||||
private boolean isCloud; |
|
||||||
//是否有广告
|
|
||||||
private boolean hasAd; |
|
||||||
//应用处于后台一段时间展示开屏广告(单位:分钟)
|
|
||||||
private int backAdTime; |
|
||||||
//应用回到前台展示广告间隔(单位:分钟)
|
|
||||||
private int intervalAdTime; |
|
||||||
//是否在详情页展示信息流广告
|
|
||||||
private boolean showFlowAd; |
|
||||||
|
|
||||||
public AdBean() { |
|
||||||
} |
|
||||||
|
|
||||||
public AdBean(boolean hasAd, int backAdTime, int intervalAdTime) { |
|
||||||
this.hasAd = hasAd; |
|
||||||
this.backAdTime = backAdTime; |
|
||||||
this.intervalAdTime = intervalAdTime; |
|
||||||
} |
|
||||||
|
|
||||||
public AdBean(boolean hasAd, int backAdTime, int intervalAdTime, boolean showFlowAd) { |
|
||||||
this.hasAd = hasAd; |
|
||||||
this.backAdTime = backAdTime; |
|
||||||
this.intervalAdTime = intervalAdTime; |
|
||||||
this.showFlowAd = showFlowAd; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isCloud() { |
|
||||||
return isCloud; |
|
||||||
} |
|
||||||
|
|
||||||
public void setCloud(boolean cloud) { |
|
||||||
isCloud = cloud; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isHasAd() { |
|
||||||
return hasAd; |
|
||||||
} |
|
||||||
|
|
||||||
public void setHasAd(boolean hasAd) { |
|
||||||
this.hasAd = hasAd; |
|
||||||
} |
|
||||||
|
|
||||||
public int getBackAdTime() { |
|
||||||
return backAdTime; |
|
||||||
} |
|
||||||
|
|
||||||
public void setBackAdTime(int backAdTime) { |
|
||||||
this.backAdTime = backAdTime; |
|
||||||
} |
|
||||||
|
|
||||||
public int getIntervalAdTime() { |
|
||||||
return intervalAdTime; |
|
||||||
} |
|
||||||
|
|
||||||
public void setIntervalAdTime(int intervalAdTime) { |
|
||||||
this.intervalAdTime = intervalAdTime; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isShowFlowAd() { |
|
||||||
return showFlowAd; |
|
||||||
} |
|
||||||
|
|
||||||
public void setShowFlowAd(boolean showFlowAd) { |
|
||||||
this.showFlowAd = showFlowAd; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,10 @@ |
|||||||
|
package xyz.fycz.myreader.entity.ad |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 15:00 |
||||||
|
*/ |
||||||
|
data class AdBean( |
||||||
|
val status: Int,// 广告展示状态:0:不展示,1:展示信息流广告,2:展示插屏广告 |
||||||
|
val interval: Int,// 广告展示间隔(单位:分钟) |
||||||
|
) |
@ -0,0 +1,137 @@ |
|||||||
|
package xyz.fycz.myreader.entity.ad; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
import xyz.fycz.myreader.util.utils.GsonExtensionsKt; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/2/17 18:56 |
||||||
|
*/ |
||||||
|
public class AdConfig { |
||||||
|
//是否云控
|
||||||
|
private boolean isCloud; |
||||||
|
//是否有广告
|
||||||
|
private boolean hasAd; |
||||||
|
//配置过期时间
|
||||||
|
private int expireTime; |
||||||
|
//应用处于后台一段时间展示开屏广告(单位:分钟)
|
||||||
|
private int backAdTime; |
||||||
|
//应用回到前台展示广告间隔(单位:分钟)
|
||||||
|
private int intervalAdTime; |
||||||
|
//单次激励视频可去广告时间(单位:小时),为0时表示关闭去广告
|
||||||
|
private int removeAdTime; |
||||||
|
//每日最大去除广告次数
|
||||||
|
private int maxRemove; |
||||||
|
//累计最高去除时间(单位:小时)
|
||||||
|
private int totalRemove; |
||||||
|
//详情页广告配置
|
||||||
|
private AdBean detail; |
||||||
|
//搜索页广告配置
|
||||||
|
private AdBean search; |
||||||
|
|
||||||
|
public AdConfig() { |
||||||
|
} |
||||||
|
|
||||||
|
public AdConfig(boolean hasAd, int expireTime, int backAdTime, int intervalAdTime, int removeAdTime, int maxRemove, int totalRemove) { |
||||||
|
this.hasAd = hasAd; |
||||||
|
this.expireTime = expireTime; |
||||||
|
this.backAdTime = backAdTime; |
||||||
|
this.intervalAdTime = intervalAdTime; |
||||||
|
this.removeAdTime = removeAdTime; |
||||||
|
this.maxRemove = maxRemove; |
||||||
|
this.totalRemove = totalRemove; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isCloud() { |
||||||
|
return isCloud; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCloud(boolean cloud) { |
||||||
|
isCloud = cloud; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isHasAd() { |
||||||
|
return hasAd; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHasAd(boolean hasAd) { |
||||||
|
this.hasAd = hasAd; |
||||||
|
} |
||||||
|
|
||||||
|
public int getBackAdTime() { |
||||||
|
return backAdTime; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBackAdTime(int backAdTime) { |
||||||
|
this.backAdTime = backAdTime; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIntervalAdTime() { |
||||||
|
return intervalAdTime; |
||||||
|
} |
||||||
|
|
||||||
|
public void setIntervalAdTime(int intervalAdTime) { |
||||||
|
this.intervalAdTime = intervalAdTime; |
||||||
|
} |
||||||
|
|
||||||
|
public int getExpireTime() { |
||||||
|
return expireTime; |
||||||
|
} |
||||||
|
|
||||||
|
public void setExpireTime(int expireTime) { |
||||||
|
this.expireTime = expireTime; |
||||||
|
} |
||||||
|
|
||||||
|
public int getRemoveAdTime() { |
||||||
|
return removeAdTime; |
||||||
|
} |
||||||
|
|
||||||
|
public void setRemoveAdTime(int removeAdTime) { |
||||||
|
this.removeAdTime = removeAdTime; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMaxRemove() { |
||||||
|
return maxRemove; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMaxRemove(int maxRemove) { |
||||||
|
this.maxRemove = maxRemove; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTotalRemove() { |
||||||
|
return totalRemove; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTotalRemove(int totalRemove) { |
||||||
|
this.totalRemove = totalRemove; |
||||||
|
} |
||||||
|
|
||||||
|
public AdBean getDetail() { |
||||||
|
if (detail == null) { |
||||||
|
detail = new AdBean(2, 60); |
||||||
|
} |
||||||
|
return detail; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDetail(AdBean detail) { |
||||||
|
this.detail = detail; |
||||||
|
} |
||||||
|
|
||||||
|
public AdBean getSearch() { |
||||||
|
if (search == null) { |
||||||
|
search = new AdBean(0, 60); |
||||||
|
} |
||||||
|
return search; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSearch(AdBean search) { |
||||||
|
this.search = search; |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return GsonExtensionsKt.getGSON().toJson(this); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package xyz.fycz.myreader.entity.lanzou |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 8:53 |
||||||
|
*/ |
||||||
|
data class LanZouFile( |
||||||
|
var id: String, |
||||||
|
var name_all: String, |
||||||
|
var size: String, |
||||||
|
var time: String |
||||||
|
) |
@ -1,10 +1,10 @@ |
|||||||
package xyz.fycz.myreader.entity |
package xyz.fycz.myreader.entity.lanzou |
||||||
|
|
||||||
/** |
/** |
||||||
* @author fengyue |
* @author fengyue |
||||||
* @date 2022/1/22 20:15 |
* @date 2022/1/22 20:15 |
||||||
*/ |
*/ |
||||||
data class LanZouBean( |
data class LanZouParseBean( |
||||||
var zt: Int, |
var zt: Int, |
||||||
var dom: String, |
var dom: String, |
||||||
var url: String, |
var url: String, |
@ -0,0 +1,77 @@ |
|||||||
|
package xyz.fycz.myreader.greendao.entity; |
||||||
|
|
||||||
|
import org.greenrobot.greendao.annotation.Entity; |
||||||
|
import org.greenrobot.greendao.annotation.Id; |
||||||
|
import org.greenrobot.greendao.annotation.Generated; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 14:40 |
||||||
|
*/ |
||||||
|
@Entity |
||||||
|
public class SubscribeFile { |
||||||
|
@Id |
||||||
|
private String id; |
||||||
|
|
||||||
|
private String name; |
||||||
|
|
||||||
|
private String url; |
||||||
|
|
||||||
|
private String date; |
||||||
|
|
||||||
|
private String size; |
||||||
|
|
||||||
|
@Generated(hash = 1850023033) |
||||||
|
public SubscribeFile(String id, String name, String url, String date, |
||||||
|
String size) { |
||||||
|
this.id = id; |
||||||
|
this.name = name; |
||||||
|
this.url = url; |
||||||
|
this.date = date; |
||||||
|
this.size = size; |
||||||
|
} |
||||||
|
|
||||||
|
@Generated(hash = 1590903919) |
||||||
|
public SubscribeFile() { |
||||||
|
} |
||||||
|
|
||||||
|
public String getId() { |
||||||
|
return this.id; |
||||||
|
} |
||||||
|
|
||||||
|
public void setId(String id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return this.name; |
||||||
|
} |
||||||
|
|
||||||
|
public void setName(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
public String getUrl() { |
||||||
|
return this.url; |
||||||
|
} |
||||||
|
|
||||||
|
public void setUrl(String url) { |
||||||
|
this.url = url; |
||||||
|
} |
||||||
|
|
||||||
|
public String getDate() { |
||||||
|
return this.date; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDate(String date) { |
||||||
|
this.date = date; |
||||||
|
} |
||||||
|
|
||||||
|
public String getSize() { |
||||||
|
return this.size; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSize(String size) { |
||||||
|
this.size = size; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
package xyz.fycz.myreader.ui.activity |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import androidx.appcompat.widget.Toolbar |
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager |
||||||
|
import xyz.fycz.myreader.R |
||||||
|
import xyz.fycz.myreader.base.BaseActivity |
||||||
|
import xyz.fycz.myreader.base.adapter.BaseListAdapter |
||||||
|
import xyz.fycz.myreader.base.adapter.IViewHolder |
||||||
|
import xyz.fycz.myreader.common.URLCONST |
||||||
|
import xyz.fycz.myreader.databinding.ActivitySourceSubscribeBinding |
||||||
|
import xyz.fycz.myreader.entity.lanzou.LanZouFile |
||||||
|
import xyz.fycz.myreader.greendao.entity.SubscribeFile |
||||||
|
import xyz.fycz.myreader.ui.adapter.holder.SourceFileHolder |
||||||
|
import xyz.fycz.myreader.util.ToastUtils |
||||||
|
import xyz.fycz.myreader.webapi.LanZouApi |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 9:56 |
||||||
|
*/ |
||||||
|
class SourceSubscribeActivity : BaseActivity() { |
||||||
|
private lateinit var binding: ActivitySourceSubscribeBinding |
||||||
|
private lateinit var fileAdapter: BaseListAdapter<SubscribeFile> |
||||||
|
private var page = 1 |
||||||
|
|
||||||
|
override fun bindView() { |
||||||
|
binding = ActivitySourceSubscribeBinding.inflate(layoutInflater) |
||||||
|
setContentView(binding.root) |
||||||
|
} |
||||||
|
|
||||||
|
override fun setUpToolbar(toolbar: Toolbar?) { |
||||||
|
super.setUpToolbar(toolbar) |
||||||
|
setStatusBarColor(R.color.colorPrimary, true) |
||||||
|
supportActionBar?.title = "书源订阅" |
||||||
|
} |
||||||
|
|
||||||
|
override fun initData(savedInstanceState: Bundle?) { |
||||||
|
super.initData(savedInstanceState) |
||||||
|
fileAdapter = object : BaseListAdapter<SubscribeFile>() { |
||||||
|
override fun createViewHolder(viewType: Int): IViewHolder<SubscribeFile> { |
||||||
|
return SourceFileHolder() |
||||||
|
} |
||||||
|
} |
||||||
|
binding.rvFiles.layoutManager = LinearLayoutManager(this) |
||||||
|
binding.rvFiles.adapter = fileAdapter |
||||||
|
loadFiles() |
||||||
|
} |
||||||
|
|
||||||
|
override fun initWidget() { |
||||||
|
super.initWidget() |
||||||
|
binding.srlFiles.setOnLoadMoreListener { loadFiles() } |
||||||
|
binding.srlFiles.setOnRefreshListener { |
||||||
|
page = 1 |
||||||
|
loadFiles() |
||||||
|
} |
||||||
|
binding.loading.setOnReloadingListener { |
||||||
|
page = 1 |
||||||
|
loadFiles() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun loadFiles() { |
||||||
|
LanZouApi.getFoldFiles(URLCONST.SUB_SOURCE_URL, page, "fm9a") |
||||||
|
.onSuccess { |
||||||
|
if (it != null) { |
||||||
|
if (page == 1) { |
||||||
|
if (it.isEmpty()) { |
||||||
|
binding.loading.showEmpty() |
||||||
|
} else { |
||||||
|
binding.loading.showFinish() |
||||||
|
fileAdapter.refreshItems(lanZouFile2SubscribeFile(it)) |
||||||
|
if (it.size < 50) { |
||||||
|
binding.srlFiles.finishRefreshWithNoMoreData() |
||||||
|
} else { |
||||||
|
binding.srlFiles.finishRefresh() |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
fileAdapter.addItems(lanZouFile2SubscribeFile(it)) |
||||||
|
if (it.size < 50) { |
||||||
|
binding.srlFiles.finishLoadMoreWithNoMoreData() |
||||||
|
} else { |
||||||
|
binding.srlFiles.finishLoadMore() |
||||||
|
} |
||||||
|
} |
||||||
|
page++ |
||||||
|
} else { |
||||||
|
binding.loading.showError() |
||||||
|
} |
||||||
|
}.onError { |
||||||
|
ToastUtils.showError("" + it.localizedMessage) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun initClick() { |
||||||
|
super.initClick() |
||||||
|
} |
||||||
|
|
||||||
|
private fun lanZouFile2SubscribeFile(lanZouFile: List<LanZouFile>): ArrayList<SubscribeFile> { |
||||||
|
val files = ArrayList<SubscribeFile>() |
||||||
|
lanZouFile.forEach { |
||||||
|
val param = it.name_all.removeSuffix(".txt").split("#") |
||||||
|
files.add( |
||||||
|
SubscribeFile( |
||||||
|
param[0], |
||||||
|
param[1], |
||||||
|
URLCONST.LAN_ZOU_URL + "/${it.id}", |
||||||
|
param[2], |
||||||
|
it.size |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
return files |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
package xyz.fycz.myreader.ui.adapter |
||||||
|
|
||||||
|
import android.widget.Filter |
||||||
|
import xyz.fycz.myreader.base.adapter.IViewHolder |
||||||
|
import xyz.fycz.myreader.greendao.entity.rule.BookSource |
||||||
|
import xyz.fycz.myreader.ui.adapter.holder.SubscribeSourceHolder |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 12:08 |
||||||
|
*/ |
||||||
|
class SubscribeSourceAdapter( |
||||||
|
val sources: List<BookSource>, |
||||||
|
private val onDelListener: OnDelListener |
||||||
|
) : BaseSourceAdapter() { |
||||||
|
override fun createViewHolder(viewType: Int): IViewHolder<BookSource> { |
||||||
|
return SubscribeSourceHolder(checkMap, onDelListener) |
||||||
|
} |
||||||
|
|
||||||
|
override fun getFilter(): Filter { |
||||||
|
return object : Filter() { |
||||||
|
override fun performFiltering(constraint: CharSequence): FilterResults { |
||||||
|
val charString = constraint.toString() |
||||||
|
var mFilterList: MutableList<BookSource> = ArrayList() |
||||||
|
if (charString.isEmpty()) { |
||||||
|
//没有过滤的内容,则使用源数据 |
||||||
|
mFilterList = sources.toMutableList() |
||||||
|
} else { |
||||||
|
for (source in sources) { |
||||||
|
//这里根据需求,添加匹配规则 |
||||||
|
if (source.sourceName.contains(charString) || |
||||||
|
source.sourceGroup.contains(charString) |
||||||
|
) { |
||||||
|
mFilterList.add(source) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
val filterResults = FilterResults() |
||||||
|
filterResults.values = mFilterList |
||||||
|
return filterResults |
||||||
|
} |
||||||
|
|
||||||
|
//把过滤后的值返回出来 |
||||||
|
override fun publishResults(constraint: CharSequence, results: FilterResults) { |
||||||
|
refreshItems(results.values as List<BookSource>) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
fun removeItem(pos: Int) { |
||||||
|
mList.removeAt(pos) |
||||||
|
notifyItemRemoved(pos) |
||||||
|
if (pos != mList.size) notifyItemRangeChanged(pos, mList.size - pos) |
||||||
|
} |
||||||
|
interface OnDelListener { |
||||||
|
fun onDel(which: Int, source: BookSource) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
package xyz.fycz.myreader.ui.adapter.holder |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.widget.TextView |
||||||
|
import androidx.recyclerview.widget.RecyclerView |
||||||
|
import xyz.fycz.myreader.R |
||||||
|
import xyz.fycz.myreader.base.adapter.ViewHolderImpl |
||||||
|
import xyz.fycz.myreader.entity.lanzou.LanZouFile |
||||||
|
import xyz.fycz.myreader.greendao.entity.SubscribeFile |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 10:17 |
||||||
|
*/ |
||||||
|
class SourceFileHolder : ViewHolderImpl<SubscribeFile>() { |
||||||
|
|
||||||
|
private lateinit var name: TextView |
||||||
|
private lateinit var sizeTime: TextView |
||||||
|
|
||||||
|
override fun getItemLayoutId(): Int { |
||||||
|
return R.layout.item_lan_zou_file |
||||||
|
} |
||||||
|
|
||||||
|
override fun initView() { |
||||||
|
name = findById(R.id.tv_file_name) |
||||||
|
sizeTime = findById(R.id.tv_file_size_time) |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n") |
||||||
|
override fun onBind(holder: RecyclerView.ViewHolder?, data: SubscribeFile?, pos: Int) { |
||||||
|
data?.let { |
||||||
|
name.text = data.name |
||||||
|
sizeTime.text = "${data.size} ${data.date}" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,96 @@ |
|||||||
|
package xyz.fycz.myreader.ui.adapter.holder |
||||||
|
|
||||||
|
import android.widget.CheckBox |
||||||
|
import android.widget.TextView |
||||||
|
import androidx.recyclerview.widget.RecyclerView |
||||||
|
import io.reactivex.Observable |
||||||
|
import io.reactivex.ObservableEmitter |
||||||
|
import io.reactivex.ObservableOnSubscribe |
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers |
||||||
|
import io.reactivex.schedulers.Schedulers |
||||||
|
import xyz.fycz.myreader.R |
||||||
|
import xyz.fycz.myreader.base.adapter.ViewHolderImpl |
||||||
|
import xyz.fycz.myreader.base.adapter2.onClick |
||||||
|
import xyz.fycz.myreader.base.observer.MyObserver |
||||||
|
import xyz.fycz.myreader.greendao.DbManager |
||||||
|
import xyz.fycz.myreader.greendao.entity.rule.BookSource |
||||||
|
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager |
||||||
|
import xyz.fycz.myreader.ui.adapter.SubscribeSourceAdapter |
||||||
|
import xyz.fycz.myreader.util.ToastUtils |
||||||
|
import xyz.fycz.myreader.util.help.StringHelper |
||||||
|
import xyz.fycz.myreader.util.utils.RxUtils |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 12:11 |
||||||
|
*/ |
||||||
|
class SubscribeSourceHolder( |
||||||
|
private val mCheckMap: HashMap<BookSource, Boolean>, |
||||||
|
private val onDelListener: SubscribeSourceAdapter.OnDelListener |
||||||
|
) : ViewHolderImpl<BookSource>() { |
||||||
|
|
||||||
|
private var cbSource: CheckBox? = null |
||||||
|
private var tvEnable: TextView? = null |
||||||
|
private var tvDisable: TextView? = null |
||||||
|
private var tvDelete: TextView? = null |
||||||
|
|
||||||
|
override fun getItemLayoutId(): Int { |
||||||
|
return R.layout.item_subscribe_source |
||||||
|
} |
||||||
|
|
||||||
|
override fun initView() { |
||||||
|
cbSource = findById(R.id.cb_source) |
||||||
|
tvEnable = findById(R.id.tv_enable) |
||||||
|
tvDisable = findById(R.id.tv_disable) |
||||||
|
tvDelete = findById(R.id.tv_delete) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onBind(holder: RecyclerView.ViewHolder, data: BookSource, pos: Int) { |
||||||
|
banOrUse(data) |
||||||
|
cbSource?.isChecked = mCheckMap[data] == true |
||||||
|
tvEnable?.onClick { |
||||||
|
data.enable = true |
||||||
|
banOrUse(data) |
||||||
|
DbManager.getDaoSession().bookSourceDao.insertOrReplace(data) |
||||||
|
} |
||||||
|
tvDisable?.onClick { |
||||||
|
data.enable = false |
||||||
|
banOrUse(data) |
||||||
|
DbManager.getDaoSession().bookSourceDao.insertOrReplace(data) |
||||||
|
} |
||||||
|
tvDelete?.onClick { |
||||||
|
Observable.create { e: ObservableEmitter<Boolean?> -> |
||||||
|
BookSourceManager.removeBookSource(data) |
||||||
|
e.onNext(true) |
||||||
|
}.compose { RxUtils.toSimpleSingle(it) } |
||||||
|
.subscribe(object : MyObserver<Boolean?>() { |
||||||
|
override fun onNext(aBoolean: Boolean) { |
||||||
|
onDelListener.onDel(pos, data) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onError(e: Throwable) { |
||||||
|
ToastUtils.showError("删除失败") |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun banOrUse(data: BookSource) { |
||||||
|
if (data.enable) { |
||||||
|
cbSource?.setTextColor(context.resources.getColor(R.color.textPrimary)) |
||||||
|
if (!StringHelper.isEmpty(data.sourceGroup)) { |
||||||
|
cbSource?.text = String.format("%s [%s]", data.sourceName, data.sourceGroup) |
||||||
|
} else { |
||||||
|
cbSource?.text = data.sourceName |
||||||
|
} |
||||||
|
} else { |
||||||
|
cbSource?.setTextColor(context.resources.getColor(R.color.textSecondary)) |
||||||
|
if (!StringHelper.isEmpty(data.sourceGroup)) { |
||||||
|
cbSource?.text = String.format("(禁用中)%s [%s]", data.sourceName, data.sourceGroup) |
||||||
|
} else { |
||||||
|
cbSource?.text = String.format("(禁用中)%s", data.sourceName) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,202 @@ |
|||||||
|
package xyz.fycz.myreader.ui.fragment |
||||||
|
|
||||||
|
import android.content.DialogInterface |
||||||
|
import android.content.Intent |
||||||
|
import android.os.Bundle |
||||||
|
import android.view.* |
||||||
|
import android.widget.PopupMenu |
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager |
||||||
|
import io.reactivex.Single |
||||||
|
import io.reactivex.SingleEmitter |
||||||
|
import xyz.fycz.myreader.R |
||||||
|
import xyz.fycz.myreader.base.BaseFragment |
||||||
|
import xyz.fycz.myreader.base.adapter2.onClick |
||||||
|
import xyz.fycz.myreader.base.observer.MySingleObserver |
||||||
|
import xyz.fycz.myreader.databinding.FragmentSubscribeSourceBinding |
||||||
|
import xyz.fycz.myreader.greendao.DbManager |
||||||
|
import xyz.fycz.myreader.greendao.entity.rule.BookSource |
||||||
|
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager |
||||||
|
import xyz.fycz.myreader.ui.activity.BookSourceActivity |
||||||
|
import xyz.fycz.myreader.ui.activity.SourceSubscribeActivity |
||||||
|
import xyz.fycz.myreader.ui.adapter.SubscribeSourceAdapter |
||||||
|
import xyz.fycz.myreader.ui.dialog.DialogCreator |
||||||
|
import xyz.fycz.myreader.util.ToastUtils |
||||||
|
import xyz.fycz.myreader.util.utils.RxUtils |
||||||
|
import xyz.fycz.myreader.widget.DividerItemDecoration |
||||||
|
import java.util.ArrayList |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2022/3/3 11:36 |
||||||
|
*/ |
||||||
|
class SubscribeSourceFragment(private val sourceActivity: BookSourceActivity) : BaseFragment() { |
||||||
|
private lateinit var binding: FragmentSubscribeSourceBinding |
||||||
|
private var mBookSources: MutableList<BookSource>? = null |
||||||
|
private var mAdapter: SubscribeSourceAdapter? = null |
||||||
|
private var featuresMenu: PopupMenu? = null |
||||||
|
override fun bindView(inflater: LayoutInflater, container: ViewGroup): View { |
||||||
|
binding = FragmentSubscribeSourceBinding.inflate(inflater, container, false) |
||||||
|
return binding.root |
||||||
|
} |
||||||
|
|
||||||
|
override fun initData(savedInstanceState: Bundle?) { |
||||||
|
super.initData(savedInstanceState) |
||||||
|
Single.create { emitter: SingleEmitter<List<BookSource>> -> |
||||||
|
emitter.onSuccess(BookSourceManager.getAllLocalSource()) |
||||||
|
}.compose { RxUtils.toSimpleSingle(it) } |
||||||
|
.subscribe(object : MySingleObserver<List<BookSource>>() { |
||||||
|
override fun onSuccess(sources: List<BookSource>) { |
||||||
|
mBookSources = sources.toMutableList() |
||||||
|
initSourceList() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onError(e: Throwable) { |
||||||
|
ToastUtils.showError(" 数据加载失败\n${e.localizedMessage}") |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
private fun initSourceList() { |
||||||
|
mAdapter = |
||||||
|
SubscribeSourceAdapter(mBookSources!!, object : SubscribeSourceAdapter.OnDelListener { |
||||||
|
override fun onDel(which: Int, source: BookSource) { |
||||||
|
mBookSources?.remove(source) |
||||||
|
mAdapter?.removeItem(which) |
||||||
|
} |
||||||
|
}) |
||||||
|
mAdapter?.setOnItemClickListener { _, pos -> |
||||||
|
mAdapter?.setCheckedItem(pos) |
||||||
|
} |
||||||
|
binding.recyclerView.layoutManager = LinearLayoutManager(context) |
||||||
|
binding.recyclerView.adapter = mAdapter |
||||||
|
//设置分割线 |
||||||
|
binding.recyclerView.addItemDecoration(DividerItemDecoration(context)) |
||||||
|
mAdapter?.refreshItems(mBookSources) |
||||||
|
} |
||||||
|
|
||||||
|
override fun initWidget(savedInstanceState: Bundle?) { |
||||||
|
super.initWidget(savedInstanceState) |
||||||
|
} |
||||||
|
|
||||||
|
override fun initClick() { |
||||||
|
super.initClick() |
||||||
|
binding.tvSubscribeSource.onClick { |
||||||
|
startActivity(Intent(context, SourceSubscribeActivity::class.java)) |
||||||
|
} |
||||||
|
binding.ivGroup.setOnClickListener { view: View? -> |
||||||
|
showSourceGroupMenu(view) |
||||||
|
} |
||||||
|
binding.ivMenu.setOnClickListener { v -> |
||||||
|
if (featuresMenu == null) { |
||||||
|
initFeaturesMenu(v) |
||||||
|
} |
||||||
|
featuresMenu?.show() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 显示书源分组菜单 |
||||||
|
*/ |
||||||
|
private fun showSourceGroupMenu(view: View?) { |
||||||
|
val popupMenu = PopupMenu(sourceActivity, view, Gravity.END) |
||||||
|
val groupList = BookSourceManager.getGroupList(true) |
||||||
|
popupMenu.menu.add(0, 0, 0, "所有书源") |
||||||
|
for (i in groupList.indices) { |
||||||
|
popupMenu.menu.add(0, 0, i + 1, groupList[i]) |
||||||
|
} |
||||||
|
popupMenu.setOnMenuItemClickListener { menuItem: MenuItem -> |
||||||
|
if (menuItem.order > 0) { |
||||||
|
sourceActivity.searchView.onActionViewExpanded() |
||||||
|
sourceActivity.searchView.clearFocus() |
||||||
|
sourceActivity.searchView.setQuery(menuItem.title, false) |
||||||
|
} else { |
||||||
|
sourceActivity.searchView.onActionViewCollapsed() |
||||||
|
} |
||||||
|
true |
||||||
|
} |
||||||
|
popupMenu.show() |
||||||
|
} |
||||||
|
|
||||||
|
private fun initFeaturesMenu(view: View) { |
||||||
|
featuresMenu = PopupMenu(sourceActivity, view, Gravity.END) |
||||||
|
//获取菜单填充器 |
||||||
|
val inflater = featuresMenu?.menuInflater |
||||||
|
//填充菜单 |
||||||
|
inflater?.inflate(R.menu.menu_subscribe_source, featuresMenu?.menu) |
||||||
|
featuresMenu?.setOnMenuItemClickListener { item: MenuItem -> |
||||||
|
when (item.itemId) { |
||||||
|
R.id.action_select_all -> { |
||||||
|
mAdapter?.setCheckedAll(true) |
||||||
|
} |
||||||
|
R.id.action_reverse_selected -> { |
||||||
|
mAdapter?.reverseChecked() |
||||||
|
} |
||||||
|
R.id.action_reverse_enable_selected -> { |
||||||
|
val bookSources = |
||||||
|
mAdapter?.checkedBookSources |
||||||
|
reverseSources(bookSources) |
||||||
|
} |
||||||
|
R.id.action_delete_selected -> { |
||||||
|
val bookSources = |
||||||
|
mAdapter?.checkedBookSources |
||||||
|
deleteSources(bookSources, false) |
||||||
|
} |
||||||
|
} |
||||||
|
true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun reverseSources(mBookSources: MutableList<BookSource>?) { |
||||||
|
if (mBookSources != null) { |
||||||
|
for (source in mBookSources) { |
||||||
|
source.enable = !source.enable |
||||||
|
} |
||||||
|
DbManager.getDaoSession().bookSourceDao.insertOrReplaceInTx(mBookSources) |
||||||
|
mAdapter?.notifyDataSetChanged() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun deleteSources(mBookSources: MutableList<BookSource>?, isDisabled: Boolean) { |
||||||
|
if (mBookSources == null || mBookSources.size == 0) { |
||||||
|
ToastUtils.showWarring("当前没有选择任何书源,无法删除!") |
||||||
|
return |
||||||
|
} |
||||||
|
val title: String |
||||||
|
val msg: String |
||||||
|
val successTip: String |
||||||
|
if (isDisabled) { |
||||||
|
title = "删除禁用书源" |
||||||
|
msg = "确定要删除所有禁用书源吗?" |
||||||
|
successTip = "禁用书源删除成功" |
||||||
|
} else { |
||||||
|
title = "删除选中书源" |
||||||
|
msg = "确定要删除所有选中书源吗?" |
||||||
|
successTip = "选中书源删除成功" |
||||||
|
} |
||||||
|
DialogCreator.createCommonDialog( |
||||||
|
sourceActivity, title, |
||||||
|
msg, true, |
||||||
|
{ _: DialogInterface?, _: Int -> |
||||||
|
val sources: MutableList<BookSource> = |
||||||
|
ArrayList() |
||||||
|
if (isDisabled) { |
||||||
|
for (source in mBookSources) { |
||||||
|
if (!source.enable) { |
||||||
|
sources.add(source) |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
sources.addAll(mBookSources) |
||||||
|
} |
||||||
|
BookSourceManager.removeBookSources(sources) |
||||||
|
mBookSources.removeAll(sources) |
||||||
|
mAdapter?.removeItems(sources) |
||||||
|
ToastUtils.showSuccess(successTip) |
||||||
|
}, null |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
fun startSearch(newText: String?) { |
||||||
|
mAdapter?.filter?.filter(newText) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<LinearLayout 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="match_parent" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<include layout="@layout/toolbar" /> |
||||||
|
|
||||||
|
<xyz.fycz.myreader.widget.RefreshLayout |
||||||
|
android:id="@+id/loading" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<com.scwang.smartrefresh.layout.SmartRefreshLayout |
||||||
|
android:id="@+id/srl_files" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:descendantFocusability="blocksDescendants"> |
||||||
|
|
||||||
|
<com.scwang.smartrefresh.header.MaterialHeader |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" /> |
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView |
||||||
|
android:id="@+id/rv_files" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" /> |
||||||
|
|
||||||
|
<com.scwang.smartrefresh.layout.footer.ClassicsFooter |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
app:srlAccentColor="@color/textSecondary" |
||||||
|
app:srlTextFailed="@string/loading_tip" |
||||||
|
app:srlTextLoading="@string/loading_tip" |
||||||
|
app:srlTextNothing="总得有个结尾吧" /> |
||||||
|
</com.scwang.smartrefresh.layout.SmartRefreshLayout> |
||||||
|
|
||||||
|
</xyz.fycz.myreader.widget.RefreshLayout> |
||||||
|
</LinearLayout> |
@ -0,0 +1,86 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<LinearLayout 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="match_parent" |
||||||
|
android:background="@color/colorForeground" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<RelativeLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="35dp" |
||||||
|
android:orientation="horizontal"> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_alignParentStart="true" |
||||||
|
android:orientation="horizontal"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_subscribe_source" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:paddingStart="10dp" |
||||||
|
android:paddingEnd="10dp" |
||||||
|
android:text="@string/subscribe_source" |
||||||
|
android:textColor="@color/colorAccent" |
||||||
|
android:textSize="@dimen/text_small_size" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_subscribe_source_tip" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:paddingStart="10dp" |
||||||
|
android:paddingEnd="10dp" |
||||||
|
android:text="@string/subscribe_source_tip" |
||||||
|
android:textColor="@color/colorAccent" |
||||||
|
android:textSize="@dimen/text_small_size" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_group" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_toStartOf="@+id/iv_menu" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:paddingStart="5dp" |
||||||
|
android:paddingEnd="5dp" |
||||||
|
app:srcCompat="@drawable/ic_filter" |
||||||
|
app:tint="@color/colorAccent" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_menu" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_alignParentEnd="true" |
||||||
|
android:layout_gravity="end" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:paddingStart="5dp" |
||||||
|
android:paddingEnd="5dp" |
||||||
|
app:srcCompat="@drawable/ic_menu" |
||||||
|
app:tint="@color/colorAccent" /> |
||||||
|
|
||||||
|
</RelativeLayout> |
||||||
|
|
||||||
|
<View |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="1dp" |
||||||
|
android:background="@color/colorBackground" /> |
||||||
|
|
||||||
|
<RelativeLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent"> |
||||||
|
|
||||||
|
<xyz.fycz.myreader.widget.scroller.FastScrollRecyclerView |
||||||
|
android:id="@+id/recycler_view" |
||||||
|
android:background="@color/colorForeground" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" /> |
||||||
|
</RelativeLayout> |
||||||
|
</LinearLayout> |
@ -0,0 +1,36 @@ |
|||||||
|
<?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="wrap_content" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:paddingHorizontal="5dp" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="vertical" |
||||||
|
android:paddingVertical="10dp" |
||||||
|
android:paddingHorizontal="5dp"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/tv_file_name" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:textColor="@color/textPrimary" |
||||||
|
android:textSize="@dimen/text_normal_size" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/tv_file_size_time" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:textColor="@color/textSecondary" |
||||||
|
android:textSize="@dimen/text_small_size" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
|
||||||
|
<View |
||||||
|
android:layout_width="fill_parent" |
||||||
|
android:layout_height="0.5dp" |
||||||
|
android:background="@color/sys_window_back" /> |
||||||
|
</LinearLayout> |
@ -0,0 +1,60 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="50dp" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:paddingStart="10dp" |
||||||
|
android:paddingEnd="10dp"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatCheckBox |
||||||
|
android:id="@+id/cb_source" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_alignParentStart="true" |
||||||
|
android:layout_toStartOf="@+id/tv_enable" |
||||||
|
android:clickable="false" |
||||||
|
android:textColor="@color/textPrimary" |
||||||
|
android:ellipsize="end" |
||||||
|
android:maxLines="2" |
||||||
|
android:textSize="@dimen/text_normal_size" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_enable" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_toStartOf="@+id/tv_disable" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:gravity="center" |
||||||
|
android:paddingStart="5dp" |
||||||
|
android:paddingEnd="5dp" |
||||||
|
android:text="@string/enable_use" |
||||||
|
android:textColor="@color/textSecondary" |
||||||
|
android:textSize="@dimen/text_small_size" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_disable" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_toStartOf="@+id/tv_delete" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:gravity="center" |
||||||
|
android:paddingStart="5dp" |
||||||
|
android:paddingEnd="5dp" |
||||||
|
android:text="@string/ban" |
||||||
|
android:textColor="@color/textSecondary" |
||||||
|
android:textSize="@dimen/text_small_size" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_delete" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_alignParentEnd="true" |
||||||
|
android:background="?android:attr/selectableItemBackground" |
||||||
|
android:gravity="center" |
||||||
|
android:paddingStart="5dp" |
||||||
|
android:paddingEnd="5dp" |
||||||
|
android:text="@string/delete" |
||||||
|
android:textColor="@color/textSecondary" |
||||||
|
android:textSize="@dimen/text_small_size" /> |
||||||
|
</RelativeLayout> |
@ -0,0 +1,18 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item |
||||||
|
android:id="@+id/action_select_all" |
||||||
|
android:title="@string/select_all" /> |
||||||
|
<item |
||||||
|
android:id="@+id/action_reverse_selected" |
||||||
|
android:title="@string/reverse_selected" /> |
||||||
|
|
||||||
|
<item |
||||||
|
android:id="@+id/action_reverse_enable_selected" |
||||||
|
android:title="@string/reverse_enable_selected" /> |
||||||
|
|
||||||
|
<item |
||||||
|
android:id="@+id/action_delete_selected" |
||||||
|
android:title="@string/delete_selected" /> |
||||||
|
|
||||||
|
</menu> |
Loading…
Reference in new issue