diff --git a/app/src/main/assets/help/appHelp.md b/app/src/main/assets/help/appHelp.md
index 78dd3e976..c58c91b55 100644
--- a/app/src/main/assets/help/appHelp.md
+++ b/app/src/main/assets/help/appHelp.md
@@ -5,7 +5,7 @@
【温馨提醒】 *本帮助可以在我的-右上角帮助按钮再次打开,更新前一定要做好备份,以免数据丢失!*
1. 为什么第一次安装好之后什么东西都没有?
-* 阅读只是一个转码工具,不提供内容,第一次安装app,需要自己手动导入书源,可以从公众号[开源阅读]()、QQ群、酷安评论里获取由书友制作分享的书源。
+* 阅读只是一个转码工具,不提供内容,第一次安装app,需要自己手动导入书源,可以从公众号**[开源阅读]**、QQ群、酷安评论里获取由书友制作分享的书源。
2. 正文出现缺字漏字、内容缺失、排版错乱等情况,如何处理?
* 有可能是净化规则出现问题,先关闭替换净化并刷新,再观察是否正常。如果正常说明净化规则存在误杀,如果关闭后仍然出现相关问题,请点击源链接查看原文与正文是否相同,如果不同,再进行反馈。
diff --git a/app/src/main/assets/help/sourceHelp.md b/app/src/main/assets/help/sourceHelp.md
new file mode 100644
index 000000000..e4453db33
--- /dev/null
+++ b/app/src/main/assets/help/sourceHelp.md
@@ -0,0 +1,5 @@
+# 源规则帮助
+
+* [书源帮助文档](https://alanskycn.gitee.io/teachme/Rule/source.html)
+* [订阅源帮助文档](https://alanskycn.gitee.io/teachme/Rule/rss.html)
+
diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md
index da8aa319c..945e27da4 100644
--- a/app/src/main/assets/updateLog.md
+++ b/app/src/main/assets/updateLog.md
@@ -1,6 +1,6 @@
# 更新日志
-* 关注公众号 **[开源阅读]()** 菜单•软件下载 提前享受新版本。
-* 关注合作公众号 **[小说拾遗]()** 获取好看的小说。
+* 关注公众号 **[开源阅读]** 菜单•软件下载 提前享受新版本。
+* 关注合作公众号 **[小说拾遗]** 获取好看的小说。
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
**2020/11/18**
diff --git a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt
index 3c68bece1..760e8efd1 100644
--- a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt
+++ b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt
@@ -13,7 +13,6 @@ import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.model.analyzeRule.QueryTTF
import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.htmlFormat
-import io.legado.app.utils.toStringArray
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext
diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
index fa4a12f0a..6a90c89f7 100644
--- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
@@ -390,13 +390,18 @@ class BookSourceEditActivity :
selector(getString(R.string.help), items) { _, index ->
when (index) {
0 -> insertText(AppConst.urlOption)
- 1 -> openUrl("https://alanskycn.gitee.io/teachme/Rule/source.html")
+ 1 -> showSourceHelp()
2 -> showRegexHelp()
3 -> FilePicker.selectFile(this, selectPathRequestCode)
}
}
}
+ private fun showSourceHelp() {
+ val mdText = String(assets.open("help/sourceHelp.md").readBytes())
+ TextDialog.show(supportFragmentManager, mdText, TextDialog.MD)
+ }
+
private fun showRegexHelp() {
val mdText = String(assets.open("help/regexHelp.md").readBytes())
TextDialog.show(supportFragmentManager, mdText, TextDialog.MD)
diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt
index aa7a2db15..dbcc4b0b1 100644
--- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt
@@ -21,7 +21,10 @@ import io.legado.app.ui.qrcode.QrCodeActivity
import io.legado.app.ui.rss.source.debug.RssSourceDebugActivity
import io.legado.app.ui.widget.KeyboardToolPop
import io.legado.app.ui.widget.dialog.TextDialog
-import io.legado.app.utils.*
+import io.legado.app.utils.GSON
+import io.legado.app.utils.getViewModel
+import io.legado.app.utils.sendToClip
+import io.legado.app.utils.shareWithQr
import kotlinx.android.synthetic.main.activity_rss_source_edit.*
import org.jetbrains.anko.*
import kotlin.math.abs
@@ -199,12 +202,17 @@ class RssSourceEditActivity :
selector(getString(R.string.help), items) { _, index ->
when (index) {
0 -> insertText(AppConst.urlOption)
- 1 -> openUrl("https://alanskycn.gitee.io/teachme/Rule/rss.html")
+ 1 -> showSourceHelp()
2 -> showRegexHelp()
}
}
}
+ private fun showSourceHelp() {
+ val mdText = String(assets.open("help/sourceHelp.md").readBytes())
+ TextDialog.show(supportFragmentManager, mdText, TextDialog.MD)
+ }
+
private fun showRegexHelp() {
val mdText = String(assets.open("help/regexHelp.md").readBytes())
TextDialog.show(supportFragmentManager, mdText, TextDialog.MD)
diff --git a/app/src/main/java/io/legado/app/ui/widget/text/BetterLinkMovementMethod.kt b/app/src/main/java/io/legado/app/ui/widget/text/BetterLinkMovementMethod.kt
new file mode 100644
index 000000000..da4ea65eb
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/widget/text/BetterLinkMovementMethod.kt
@@ -0,0 +1,437 @@
+package io.legado.app.ui.widget.text
+
+import android.app.Activity
+import android.graphics.RectF
+import android.text.Selection
+import android.text.Spannable
+import android.text.Spanned
+import android.text.method.LinkMovementMethod
+import android.text.style.BackgroundColorSpan
+import android.text.style.ClickableSpan
+import android.text.style.URLSpan
+import android.text.util.Linkify
+import android.view.*
+import android.widget.TextView
+import io.legado.app.R
+import io.legado.app.ui.widget.text.BetterLinkMovementMethod.LongPressTimer.OnTimerReachedListener
+
+class BetterLinkMovementMethod protected constructor() : LinkMovementMethod() {
+ private var onLinkClickListener: OnLinkClickListener? = null
+ private var onLinkLongClickListener: OnLinkLongClickListener? = null
+ private val touchedLineBounds = RectF()
+ private var isUrlHighlighted = false
+ private var clickableSpanUnderTouchOnActionDown: ClickableSpan? = null
+ private var activeTextViewHashcode = 0
+ private var ongoingLongPressTimer: LongPressTimer? = null
+ private var wasLongPressRegistered = false
+
+ interface OnLinkClickListener {
+ /**
+ * @param textView The TextView on which a click was registered.
+ * @param url The clicked URL.
+ * @return True if this click was handled. False to let Android handle the URL.
+ */
+ fun onClick(textView: TextView?, url: String?): Boolean
+ }
+
+ interface OnLinkLongClickListener {
+ /**
+ * @param textView The TextView on which a long-click was registered.
+ * @param url The long-clicked URL.
+ * @return True if this long-click was handled. False to let Android handle the URL (as a short-click).
+ */
+ fun onLongClick(textView: TextView?, url: String?): Boolean
+ }
+
+ /**
+ * Set a listener that will get called whenever any link is clicked on the TextView.
+ */
+ fun setOnLinkClickListener(clickListener: OnLinkClickListener?): BetterLinkMovementMethod {
+ if (this === singleInstance) {
+ throw UnsupportedOperationException(
+ "Setting a click listener on the instance returned by getInstance() is not supported to avoid memory " +
+ "leaks. Please use newInstance() or any of the linkify() methods instead."
+ )
+ }
+ onLinkClickListener = clickListener
+ return this
+ }
+
+ /**
+ * Set a listener that will get called whenever any link is clicked on the TextView.
+ */
+ fun setOnLinkLongClickListener(longClickListener: OnLinkLongClickListener?): BetterLinkMovementMethod {
+ if (this === singleInstance) {
+ throw UnsupportedOperationException(
+ "Setting a long-click listener on the instance returned by getInstance() is not supported to avoid " +
+ "memory leaks. Please use newInstance() or any of the linkify() methods instead."
+ )
+ }
+ onLinkLongClickListener = longClickListener
+ return this
+ }
+
+ override fun onTouchEvent(textView: TextView, text: Spannable, event: MotionEvent): Boolean {
+ if (activeTextViewHashcode != textView.hashCode()) {
+ // Bug workaround: TextView stops calling onTouchEvent() once any URL is highlighted.
+ // A hacky solution is to reset any "autoLink" property set in XML. But we also want
+ // to do this once per TextView.
+ activeTextViewHashcode = textView.hashCode()
+ textView.autoLinkMask = 0
+ }
+ val clickableSpanUnderTouch = findClickableSpanUnderTouch(textView, text, event)
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ clickableSpanUnderTouchOnActionDown = clickableSpanUnderTouch
+ }
+ val touchStartedOverAClickableSpan = clickableSpanUnderTouchOnActionDown != null
+ return when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ clickableSpanUnderTouch?.let { highlightUrl(textView, it, text) }
+ if (touchStartedOverAClickableSpan && onLinkLongClickListener != null) {
+ val longClickListener: OnTimerReachedListener =
+ object : OnTimerReachedListener {
+ override fun onTimerReached() {
+ wasLongPressRegistered = true
+ textView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
+ removeUrlHighlightColor(textView)
+ dispatchUrlLongClick(textView, clickableSpanUnderTouch)
+ }
+ }
+ startTimerForRegisteringLongClick(textView, longClickListener)
+ }
+ touchStartedOverAClickableSpan
+ }
+ MotionEvent.ACTION_UP -> {
+ // Register a click only if the touch started and ended on the same URL.
+ if (!wasLongPressRegistered && touchStartedOverAClickableSpan && clickableSpanUnderTouch === clickableSpanUnderTouchOnActionDown) {
+ dispatchUrlClick(textView, clickableSpanUnderTouch)
+ }
+ cleanupOnTouchUp(textView)
+
+ // Consume this event even if we could not find any spans to avoid letting Android handle this event.
+ // Android's TextView implementation has a bug where links get clicked even when there is no more text
+ // next to the link and the touch lies outside its bounds in the same direction.
+ touchStartedOverAClickableSpan
+ }
+ MotionEvent.ACTION_CANCEL -> {
+ cleanupOnTouchUp(textView)
+ false
+ }
+ MotionEvent.ACTION_MOVE -> {
+ // Stop listening for a long-press as soon as the user wanders off to unknown lands.
+ if (clickableSpanUnderTouch !== clickableSpanUnderTouchOnActionDown) {
+ removeLongPressCallback(textView)
+ }
+ if (!wasLongPressRegistered) {
+ // Toggle highlight.
+ if (clickableSpanUnderTouch != null) {
+ highlightUrl(textView, clickableSpanUnderTouch, text)
+ } else {
+ removeUrlHighlightColor(textView)
+ }
+ }
+ touchStartedOverAClickableSpan
+ }
+ else -> false
+ }
+ }
+
+ private fun cleanupOnTouchUp(textView: TextView) {
+ wasLongPressRegistered = false
+ clickableSpanUnderTouchOnActionDown = null
+ removeUrlHighlightColor(textView)
+ removeLongPressCallback(textView)
+ }
+
+ /**
+ * Determines the touched location inside the TextView's text and returns the ClickableSpan found under it (if any).
+ *
+ * @return The touched ClickableSpan or null.
+ */
+ protected fun findClickableSpanUnderTouch(
+ textView: TextView,
+ text: Spannable,
+ event: MotionEvent
+ ): ClickableSpan? {
+ // So we need to find the location in text where touch was made, regardless of whether the TextView
+ // has scrollable text. That is, not the entire text is currently visible.
+ var touchX = event.x.toInt()
+ var touchY = event.y.toInt()
+
+ // Ignore padding.
+ touchX -= textView.totalPaddingLeft
+ touchY -= textView.totalPaddingTop
+
+ // Account for scrollable text.
+ touchX += textView.scrollX
+ touchY += textView.scrollY
+ val layout = textView.layout
+ val touchedLine = layout.getLineForVertical(touchY)
+ val touchOffset = layout.getOffsetForHorizontal(touchedLine, touchX.toFloat())
+ touchedLineBounds.left = layout.getLineLeft(touchedLine)
+ touchedLineBounds.top = layout.getLineTop(touchedLine).toFloat()
+ touchedLineBounds.right = layout.getLineWidth(touchedLine) + touchedLineBounds.left
+ touchedLineBounds.bottom = layout.getLineBottom(touchedLine).toFloat()
+ return if (touchedLineBounds.contains(touchX.toFloat(), touchY.toFloat())) {
+ // Find a ClickableSpan that lies under the touched area.
+ val spans = text.getSpans(touchOffset, touchOffset, ClickableSpan::class.java)
+ for (span in spans) {
+ if (span is ClickableSpan) {
+ return span
+ }
+ }
+ // No ClickableSpan found under the touched location.
+ null
+ } else {
+ // Touch lies outside the line's horizontal bounds where no spans should exist.
+ null
+ }
+ }
+
+ /**
+ * Adds a background color span at clickableSpan's location.
+ */
+ protected fun highlightUrl(textView: TextView, clickableSpan: ClickableSpan?, text: Spannable) {
+ if (isUrlHighlighted) {
+ return
+ }
+ isUrlHighlighted = true
+ val spanStart = text.getSpanStart(clickableSpan)
+ val spanEnd = text.getSpanEnd(clickableSpan)
+ val highlightSpan = BackgroundColorSpan(textView.highlightColor)
+ text.setSpan(highlightSpan, spanStart, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
+ textView.setTag(R.id.bettermovementmethod_highlight_background_span, highlightSpan)
+ Selection.setSelection(text, spanStart, spanEnd)
+ }
+
+ /**
+ * Removes the highlight color under the Url.
+ */
+ protected fun removeUrlHighlightColor(textView: TextView) {
+ if (!isUrlHighlighted) {
+ return
+ }
+ isUrlHighlighted = false
+ val text = textView.text as Spannable
+ val highlightSpan =
+ textView.getTag(R.id.bettermovementmethod_highlight_background_span) as BackgroundColorSpan
+ text.removeSpan(highlightSpan)
+ Selection.removeSelection(text)
+ }
+
+ protected fun startTimerForRegisteringLongClick(
+ textView: TextView,
+ longClickListener: OnTimerReachedListener?
+ ) {
+ ongoingLongPressTimer = LongPressTimer()
+ ongoingLongPressTimer!!.setOnTimerReachedListener(longClickListener)
+ textView.postDelayed(
+ ongoingLongPressTimer,
+ ViewConfiguration.getLongPressTimeout().toLong()
+ )
+ }
+
+ /**
+ * Remove the long-press detection timer.
+ */
+ protected fun removeLongPressCallback(textView: TextView) {
+ if (ongoingLongPressTimer != null) {
+ textView.removeCallbacks(ongoingLongPressTimer)
+ ongoingLongPressTimer = null
+ }
+ }
+
+ protected fun dispatchUrlClick(textView: TextView, clickableSpan: ClickableSpan?) {
+ val clickableSpanWithText = ClickableSpanWithText.ofSpan(textView, clickableSpan)
+ val handled = onLinkClickListener != null && onLinkClickListener!!.onClick(
+ textView,
+ clickableSpanWithText.text()
+ )
+ if (!handled) {
+ // Let Android handle this click.
+ clickableSpanWithText.span()!!.onClick(textView)
+ }
+ }
+
+ protected fun dispatchUrlLongClick(textView: TextView, clickableSpan: ClickableSpan?) {
+ val clickableSpanWithText = ClickableSpanWithText.ofSpan(textView, clickableSpan)
+ val handled = onLinkLongClickListener != null && onLinkLongClickListener!!.onLongClick(
+ textView,
+ clickableSpanWithText.text()
+ )
+ if (!handled) {
+ // Let Android handle this long click as a short-click.
+ clickableSpanWithText.span()!!.onClick(textView)
+ }
+ }
+
+ protected class LongPressTimer : Runnable {
+ private var onTimerReachedListener: OnTimerReachedListener? = null
+
+ interface OnTimerReachedListener {
+ fun onTimerReached()
+ }
+
+ override fun run() {
+ onTimerReachedListener!!.onTimerReached()
+ }
+
+ fun setOnTimerReachedListener(listener: OnTimerReachedListener?) {
+ onTimerReachedListener = listener
+ }
+ }
+
+ /**
+ * A wrapper to support all [ClickableSpan]s that may or may not provide URLs.
+ */
+ protected class ClickableSpanWithText protected constructor(
+ private val span: ClickableSpan?,
+ private val text: String
+ ) {
+ fun span(): ClickableSpan? {
+ return span
+ }
+
+ fun text(): String {
+ return text
+ }
+
+ companion object {
+ fun ofSpan(textView: TextView, span: ClickableSpan?): ClickableSpanWithText {
+ val s = textView.text as Spanned
+ val text: String
+ text = if (span is URLSpan) {
+ span.url
+ } else {
+ val start = s.getSpanStart(span)
+ val end = s.getSpanEnd(span)
+ s.subSequence(start, end).toString()
+ }
+ return ClickableSpanWithText(span, text)
+ }
+ }
+ }
+
+ companion object {
+ private var singleInstance: BetterLinkMovementMethod? = null
+ private const val LINKIFY_NONE = -2
+
+ /**
+ * Return a new instance of BetterLinkMovementMethod.
+ */
+ fun newInstance(): BetterLinkMovementMethod {
+ return BetterLinkMovementMethod()
+ }
+
+ /**
+ * @param linkifyMask One of [Linkify.ALL], [Linkify.PHONE_NUMBERS], [Linkify.MAP_ADDRESSES],
+ * [Linkify.WEB_URLS] and [Linkify.EMAIL_ADDRESSES].
+ * @param textViews The TextViews on which a [BetterLinkMovementMethod] should be registered.
+ * @return The registered [BetterLinkMovementMethod] on the TextViews.
+ */
+ fun linkify(linkifyMask: Int, vararg textViews: TextView): BetterLinkMovementMethod {
+ val movementMethod = newInstance()
+ for (textView in textViews) {
+ addLinks(linkifyMask, movementMethod, textView)
+ }
+ return movementMethod
+ }
+
+ /**
+ * Like [.linkify], but can be used for TextViews with HTML links.
+ *
+ * @param textViews The TextViews on which a [BetterLinkMovementMethod] should be registered.
+ * @return The registered [BetterLinkMovementMethod] on the TextViews.
+ */
+ fun linkifyHtml(vararg textViews: TextView): BetterLinkMovementMethod {
+ return linkify(LINKIFY_NONE, *textViews)
+ }
+
+ /**
+ * Recursively register a [BetterLinkMovementMethod] on every TextView inside a layout.
+ *
+ * @param linkifyMask One of [Linkify.ALL], [Linkify.PHONE_NUMBERS], [Linkify.MAP_ADDRESSES],
+ * [Linkify.WEB_URLS] and [Linkify.EMAIL_ADDRESSES].
+ * @return The registered [BetterLinkMovementMethod] on the TextViews.
+ */
+ fun linkify(linkifyMask: Int, viewGroup: ViewGroup): BetterLinkMovementMethod {
+ val movementMethod = newInstance()
+ rAddLinks(linkifyMask, viewGroup, movementMethod)
+ return movementMethod
+ }
+
+ /**
+ * Like [.linkify], but can be used for TextViews with HTML links.
+ *
+ * @return The registered [BetterLinkMovementMethod] on the TextViews.
+ */
+ fun linkifyHtml(viewGroup: ViewGroup): BetterLinkMovementMethod {
+ return linkify(LINKIFY_NONE, viewGroup)
+ }
+
+ /**
+ * Recursively register a [BetterLinkMovementMethod] on every TextView inside a layout.
+ *
+ * @param linkifyMask One of [Linkify.ALL], [Linkify.PHONE_NUMBERS], [Linkify.MAP_ADDRESSES],
+ * [Linkify.WEB_URLS] and [Linkify.EMAIL_ADDRESSES].
+ * @return The registered [BetterLinkMovementMethod] on the TextViews.
+ */
+ fun linkify(linkifyMask: Int, activity: Activity): BetterLinkMovementMethod {
+ // Find the layout passed to setContentView().
+ val activityLayout =
+ (activity.findViewById(Window.ID_ANDROID_CONTENT) as ViewGroup).getChildAt(0) as ViewGroup
+ val movementMethod = newInstance()
+ rAddLinks(linkifyMask, activityLayout, movementMethod)
+ return movementMethod
+ }
+
+ /**
+ * Like [.linkify], but can be used for TextViews with HTML links.
+ *
+ * @return The registered [BetterLinkMovementMethod] on the TextViews.
+ */
+ fun linkifyHtml(activity: Activity): BetterLinkMovementMethod {
+ return linkify(LINKIFY_NONE, activity)
+ }
+
+ /**
+ * Get a static instance of BetterLinkMovementMethod. Do note that registering a click listener on the returned
+ * instance is not supported because it will potentially be shared on multiple TextViews.
+ */
+ val instance: BetterLinkMovementMethod?
+ get() {
+ if (singleInstance == null) {
+ singleInstance = BetterLinkMovementMethod()
+ }
+ return singleInstance
+ }
+
+ // ======== PUBLIC APIs END ======== //
+ private fun rAddLinks(
+ linkifyMask: Int,
+ viewGroup: ViewGroup,
+ movementMethod: BetterLinkMovementMethod
+ ) {
+ for (i in 0 until viewGroup.childCount) {
+ val child = viewGroup.getChildAt(i)
+ if (child is ViewGroup) {
+ // Recursively find child TextViews.
+ rAddLinks(linkifyMask, child, movementMethod)
+ } else if (child is TextView) {
+ addLinks(linkifyMask, movementMethod, child)
+ }
+ }
+ }
+
+ private fun addLinks(
+ linkifyMask: Int,
+ movementMethod: BetterLinkMovementMethod,
+ textView: TextView
+ ) {
+ textView.movementMethod = movementMethod
+ if (linkifyMask != LINKIFY_NONE) {
+ Linkify.addLinks(textView, linkifyMask)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/ui/widget/text/InertiaScrollTextView.kt b/app/src/main/java/io/legado/app/ui/widget/text/InertiaScrollTextView.kt
index 9644b8676..d5a376893 100644
--- a/app/src/main/java/io/legado/app/ui/widget/text/InertiaScrollTextView.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/text/InertiaScrollTextView.kt
@@ -48,6 +48,7 @@ open class InertiaScrollTextView @JvmOverloads constructor(
mTouchSlop = vc.scaledTouchSlop
mMinFlingVelocity = vc.scaledMinimumFlingVelocity
mMaxFlingVelocity = vc.scaledMaximumFlingVelocity
+ movementMethod = BetterLinkMovementMethod.instance
}
fun atTop(): Boolean {
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index cc2d9c170..c80e30395 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -5,4 +5,7 @@
+
+
+
\ No newline at end of file