History
parent
82fda9394d
commit
6eea278b4d
@ -1,12 +1,41 @@
|
||||
package org.koitharu.kotatsu.core.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.*
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryWithManga
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
|
||||
|
||||
@Dao
|
||||
interface HistoryDao {
|
||||
abstract class HistoryDao {
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Transaction
|
||||
@Query("SELECT * FROM history ORDER BY :orderBy LIMIT :limit OFFSET :offset")
|
||||
abstract suspend fun getAll(offset: Int, limit: Int, orderBy: String): List<HistoryWithManga>
|
||||
|
||||
@Query("DELETE FROM history")
|
||||
abstract suspend fun clear()
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract suspend fun insert(entity: HistoryEntity): Long
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract suspend fun insertManga(manga: MangaEntity): Long
|
||||
|
||||
@Query("UPDATE history SET page = :page, chapter_id = :chapterId, updated_at = :updatedAt WHERE manga_id = :mangaId")
|
||||
abstract suspend fun update(mangaId: Long, page: Int, chapterId: Long, updatedAt: Long): Int
|
||||
|
||||
suspend fun update(entity: HistoryWithManga) = update(entity.manga.id, entity.history.page, entity.history.chapterId, entity.history.updatedAt)
|
||||
|
||||
@Transaction
|
||||
suspend open fun upsert(entity: HistoryWithManga) {
|
||||
if (update(entity) == 0) {
|
||||
insertManga(entity.manga)
|
||||
insert(entity.history)
|
||||
}
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM history")
|
||||
suspend fun getAll(): List<HistoryEntity>
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package org.koitharu.kotatsu.core.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
|
||||
@Dao
|
||||
interface TagsDao {
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM tags")
|
||||
fun getAllTags(): List<TagEntity>
|
||||
}
|
||||
@ -1,9 +1,25 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import java.util.*
|
||||
|
||||
@Entity(tableName = "history")
|
||||
data class HistoryEntity(
|
||||
@PrimaryKey val id: Long
|
||||
)
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
||||
@ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMillis(),
|
||||
@ColumnInfo(name = "updated_at") val updatedAt: Long,
|
||||
@ColumnInfo(name = "chapter_id") val chapterId: Long,
|
||||
@ColumnInfo(name = "page") val page: Int
|
||||
) {
|
||||
|
||||
fun toMangaHistory() = MangaHistory(
|
||||
createdAt = Date(createdAt),
|
||||
updatedAt = Date(updatedAt),
|
||||
chapterId = chapterId,
|
||||
page = page
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Relation
|
||||
|
||||
data class HistoryWithManga(
|
||||
@Embedded val history: HistoryEntity,
|
||||
@Relation(
|
||||
parentColumn = "manga_id",
|
||||
entityColumn = "manga_id"
|
||||
)
|
||||
val manga: MangaEntity
|
||||
)
|
||||
@ -0,0 +1,55 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.MangaState
|
||||
|
||||
@Entity(tableName = "manga")
|
||||
data class MangaEntity(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
@ColumnInfo(name = "manga_id") val id: Long,
|
||||
@ColumnInfo(name = "title") val title: String,
|
||||
@ColumnInfo(name = "localized_title") val localizedTitle: String? = null,
|
||||
@ColumnInfo(name = "url") val url: String,
|
||||
@ColumnInfo(name = "rating") val rating: Float = Manga.NO_RATING, //normalized value [0..1] or -1
|
||||
@ColumnInfo(name = "cover_url") val coverUrl: String,
|
||||
@ColumnInfo(name = "large_cover_url") val largeCoverUrl: String? = null,
|
||||
@ColumnInfo(name = "summary") val summary: String,
|
||||
@ColumnInfo(name = "state") val state: String? = null,
|
||||
@ColumnInfo(name = "source") val source: String
|
||||
) {
|
||||
|
||||
fun toManga() = Manga(
|
||||
id = this.id,
|
||||
title = this.title,
|
||||
localizedTitle = this.localizedTitle,
|
||||
summary = this.summary,
|
||||
state = this.state?.let { MangaState.valueOf(it) },
|
||||
rating = this.rating,
|
||||
url = this.url,
|
||||
coverUrl = this.coverUrl,
|
||||
largeCoverUrl = this.largeCoverUrl,
|
||||
source = MangaSource.valueOf(this.source)
|
||||
// tags = this.tags.map(TagEntity::toMangaTag).toSet()
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
fun from(manga: Manga) = MangaEntity(
|
||||
id = manga.id,
|
||||
url = manga.url,
|
||||
source = manga.source.name,
|
||||
largeCoverUrl = manga.largeCoverUrl,
|
||||
coverUrl = manga.coverUrl,
|
||||
localizedTitle = manga.localizedTitle,
|
||||
rating = manga.rating,
|
||||
state = manga.state?.name,
|
||||
summary = manga.summary,
|
||||
// tags = manga.tags.map(TagEntity.Companion::fromMangaTag),
|
||||
title = manga.title
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
|
||||
@Entity(tableName = "manga_tags", primaryKeys = ["manga_id", "tag_id"])
|
||||
data class MangaTagsEntity(
|
||||
@ColumnInfo(name = "manga_id") val mangaId: Long,
|
||||
@ColumnInfo(name = "tag_id") val tagId: Long
|
||||
)
|
||||
@ -0,0 +1,34 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.MangaTag
|
||||
import org.koitharu.kotatsu.utils.ext.longHashCode
|
||||
|
||||
@Entity(tableName = "tags")
|
||||
data class TagEntity(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
@ColumnInfo(name = "tag_id") val id: Long,
|
||||
@ColumnInfo(name = "title") val title: String,
|
||||
@ColumnInfo(name = "key") val key: String,
|
||||
@ColumnInfo(name = "source") val source: String
|
||||
) {
|
||||
|
||||
fun toMangaTag() = MangaTag(
|
||||
key = this.key,
|
||||
title = this.title,
|
||||
source = MangaSource.valueOf(this.source)
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
fun fromMangaTag(tag: MangaTag) = TagEntity(
|
||||
title = tag.title,
|
||||
key = tag.key,
|
||||
source = tag.source.name,
|
||||
id = "${tag.key}_${tag.source.name}".longHashCode()
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package org.koitharu.kotatsu.core.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@Parcelize
|
||||
data class MangaHistory(
|
||||
val createdAt: Date,
|
||||
val updatedAt: Date,
|
||||
val chapterId: Long,
|
||||
val page: Int
|
||||
) : Parcelable
|
||||
@ -0,0 +1,6 @@
|
||||
package org.koitharu.kotatsu.core.model
|
||||
|
||||
data class MangaInfo <E>(
|
||||
val manga: Manga,
|
||||
val extra: E
|
||||
)
|
||||
@ -0,0 +1,13 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.core.model.SortOrder
|
||||
|
||||
abstract class BaseMangaRepository(protected val loaderContext: MangaLoaderContext) : MangaRepository {
|
||||
|
||||
override val sortOrders: Set<SortOrder> get() = emptySet()
|
||||
|
||||
override val isSearchAvailable get() = true
|
||||
|
||||
override suspend fun getPageFullUrl(page: MangaPage) : String = page.url
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryWithManga
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import java.io.Closeable
|
||||
|
||||
class HistoryRepository() : KoinComponent, MangaRepository, Closeable {
|
||||
|
||||
private val db: MangaDatabase by inject()
|
||||
|
||||
override val sortOrders: Set<SortOrder> = setOf(SortOrder.NEWEST, SortOrder.POPULARITY)
|
||||
|
||||
override val isSearchAvailable = false
|
||||
|
||||
override suspend fun getList(
|
||||
offset: Int,
|
||||
query: String?,
|
||||
sortOrder: SortOrder?,
|
||||
tags: Set<String>?
|
||||
): List<Manga> = getHistory(offset, query, sortOrder, tags).map { x -> x.manga }
|
||||
|
||||
suspend fun getHistory(
|
||||
offset: Int,
|
||||
query: String? = null,
|
||||
sortOrder: SortOrder? = null,
|
||||
tags: Set<String>? = null
|
||||
): List<MangaInfo<MangaHistory>> {
|
||||
val entities = db.historyDao().getAll(offset, 20, "updated_by")
|
||||
return entities.map { x -> MangaInfo(x.manga.toManga(), x.history.toMangaHistory()) }
|
||||
}
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
throw UnsupportedOperationException("History repository does not support getDetails() method")
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
throw UnsupportedOperationException("History repository does not support getPages() method")
|
||||
}
|
||||
|
||||
override suspend fun getPageFullUrl(page: MangaPage) = page.url
|
||||
|
||||
suspend fun addOrUpdate(manga: Manga, chapterId: Long, page: Int) {
|
||||
val dao = db.historyDao()
|
||||
val entity = HistoryEntity(
|
||||
mangaId = manga.id,
|
||||
createdAt = System.currentTimeMillis(),
|
||||
updatedAt = System.currentTimeMillis(),
|
||||
chapterId = chapterId,
|
||||
page = page
|
||||
)
|
||||
dao.upsert(
|
||||
HistoryWithManga(
|
||||
history = entity,
|
||||
manga = MangaEntity.from(manga)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun clear() {
|
||||
db.historyDao().clear()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
db.close()
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,21 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.core.model.SortOrder
|
||||
|
||||
abstract class MangaRepository(protected val loaderContext: MangaLoaderContext) {
|
||||
interface MangaRepository {
|
||||
|
||||
open val sortOrders: Set<SortOrder> get() = emptySet()
|
||||
val sortOrders: Set<SortOrder>
|
||||
|
||||
open val isSearchAvailable get() = true
|
||||
val isSearchAvailable: Boolean
|
||||
|
||||
abstract suspend fun getList(offset: Int, query: String? = null, sortOrder: SortOrder? = null, tags: Set<String>? = null): List<Manga>
|
||||
suspend fun getList(offset: Int, query: String? = null, sortOrder: SortOrder? = null, tags: Set<String>? = null): List<Manga>
|
||||
|
||||
abstract suspend fun getDetails(manga: Manga) : Manga
|
||||
suspend fun getDetails(manga: Manga) : Manga
|
||||
|
||||
abstract suspend fun getPages(chapter: MangaChapter) : List<MangaPage>
|
||||
suspend fun getPages(chapter: MangaChapter) : List<MangaPage>
|
||||
|
||||
open suspend fun getPageFullUrl(page: MangaPage) : String = page.url
|
||||
suspend fun getPageFullUrl(page: MangaPage) : String
|
||||
}
|
||||
@ -1,21 +1,21 @@
|
||||
package org.koitharu.kotatsu.ui.main.list
|
||||
|
||||
import android.view.ViewGroup
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaInfo
|
||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
|
||||
|
||||
class MangaListAdapter(onItemClickListener: OnRecyclerItemClickListener<Manga>) :
|
||||
BaseRecyclerAdapter<Manga>(onItemClickListener) {
|
||||
class MangaListAdapter<E>(onItemClickListener: OnRecyclerItemClickListener<MangaInfo<E>>) :
|
||||
BaseRecyclerAdapter<MangaInfo<E>>(onItemClickListener) {
|
||||
|
||||
var listMode: ListMode = ListMode.LIST
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup) = when(listMode) {
|
||||
ListMode.LIST -> MangaListHolder(parent)
|
||||
ListMode.DETAILED_LIST -> MangaListDetailsHolder(parent)
|
||||
ListMode.LIST -> MangaListHolder<E>(parent)
|
||||
ListMode.DETAILED_LIST -> MangaListDetailsHolder<E>(parent)
|
||||
ListMode.GRID -> MangaGridHolder(parent)
|
||||
}
|
||||
|
||||
override fun onGetItemId(item: Manga) = item.id
|
||||
override fun onGetItemId(item: MangaInfo<E>) = item.manga.id
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package org.koitharu.kotatsu.ui.main.list.history
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.fragment_list.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.ui.main.list.MangaListFragment
|
||||
import org.koitharu.kotatsu.ui.main.list.MangaListView
|
||||
|
||||
class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<MangaHistory>{
|
||||
|
||||
private val presenter by moxyPresenter(factory = ::HistoryListPresenter)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
textView_holder.setText(R.string.history_is_empty)
|
||||
}
|
||||
|
||||
override fun onRequestMoreItems(offset: Int) {
|
||||
presenter.loadList(offset)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.opt_history, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = when(item.itemId) {
|
||||
R.id.action_clear_history -> {
|
||||
presenter.clearHistory()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun getTitle(): CharSequence? {
|
||||
return getString(R.string.history)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = HistoryListFragment()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package org.koitharu.kotatsu.ui.main.list.history
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import moxy.InjectViewState
|
||||
import okhttp3.internal.closeQuietly
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||
import org.koitharu.kotatsu.ui.main.list.MangaListView
|
||||
|
||||
@InjectViewState
|
||||
class HistoryListPresenter : BasePresenter<MangaListView<MangaHistory>>() {
|
||||
|
||||
private lateinit var repository: HistoryRepository
|
||||
|
||||
override fun onFirstViewAttach() {
|
||||
repository = HistoryRepository()
|
||||
super.onFirstViewAttach()
|
||||
}
|
||||
|
||||
fun loadList(offset: Int) {
|
||||
launch {
|
||||
viewState.onLoadingChanged(true)
|
||||
try {
|
||||
val list = withContext(Dispatchers.IO) {
|
||||
repository.getHistory(offset = offset)
|
||||
}
|
||||
if (offset == 0) {
|
||||
viewState.onListChanged(list)
|
||||
} else {
|
||||
viewState.onListAppended(list)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
viewState.onError(e)
|
||||
} finally {
|
||||
viewState.onLoadingChanged(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clearHistory() {
|
||||
launch {
|
||||
viewState.onLoadingChanged(true)
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
repository.clear()
|
||||
}
|
||||
viewState.onListChanged(emptyList())
|
||||
} catch (e: Exception) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
viewState.onError(e)
|
||||
} finally {
|
||||
viewState.onLoadingChanged(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
repository.closeQuietly()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package org.koitharu.kotatsu.ui.main.list.remote
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.fragment_list.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.ui.main.list.MangaListFragment
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class RemoteListFragment : MangaListFragment<Unit>() {
|
||||
|
||||
private val presenter by moxyPresenter(factory = ::RemoteListPresenter)
|
||||
|
||||
private val source by arg<MangaSource>(ARG_SOURCE)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
textView_holder.setText(R.string.nothing_found)
|
||||
}
|
||||
|
||||
override fun onRequestMoreItems(offset: Int) {
|
||||
presenter.loadList(source, offset)
|
||||
}
|
||||
|
||||
override fun getTitle(): CharSequence? {
|
||||
return source.title
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_SOURCE = "provider"
|
||||
|
||||
fun newInstance(provider: MangaSource) = RemoteListFragment().withArgs(1) {
|
||||
putParcelable(ARG_SOURCE, provider)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_clear_history"
|
||||
android:orderInCategory="50"
|
||||
android:title="@string/clear_history"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
Loading…
Reference in New Issue