Update parsers
This commit is contained in:
@@ -64,9 +64,16 @@ android {
|
|||||||
unitTests.returnDefaultValues = false
|
unitTests.returnDefaultValues = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
afterEvaluate {
|
||||||
|
compileDebugKotlin {
|
||||||
|
kotlinOptions {
|
||||||
|
freeCompilerArgs += ['-opt-in=kotlin.RequiresOptIn']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||||
implementation('com.github.nv95:kotatsu-parsers:f46c5add46') {
|
implementation('com.github.nv95:kotatsu-parsers:ab87a50e9b') {
|
||||||
exclude group: 'org.json', module: 'json'
|
exclude group: 'org.json', module: 'json'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.koitharu.kotatsu.core.parser
|
package org.koitharu.kotatsu.core.parser
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
import org.koitharu.kotatsu.parsers.MangaParser
|
import org.koitharu.kotatsu.parsers.MangaParser
|
||||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||||
@@ -9,6 +10,7 @@ import org.koitharu.kotatsu.parsers.model.*
|
|||||||
/**
|
/**
|
||||||
* This parser is just for parser development, it should not be used in releases
|
* This parser is just for parser development, it should not be used in releases
|
||||||
*/
|
*/
|
||||||
|
@OptIn(InternalParsersApi::class)
|
||||||
class DummyParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.DUMMY) {
|
class DummyParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.DUMMY) {
|
||||||
|
|
||||||
override val configKeyDomain: ConfigKey.Domain
|
override val configKeyDomain: ConfigKey.Domain
|
||||||
@@ -25,7 +27,7 @@ class DummyParser(override val context: MangaLoaderContext) : MangaParser(MangaS
|
|||||||
offset: Int,
|
offset: Int,
|
||||||
query: String?,
|
query: String?,
|
||||||
tags: Set<MangaTag>?,
|
tags: Set<MangaTag>?,
|
||||||
sortOrder: SortOrder?
|
sortOrder: SortOrder,
|
||||||
): List<Manga> {
|
): List<Manga> {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.koitharu.kotatsu.core.model
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun MangaSource.getLocaleTitle(): String? {
|
||||||
|
val lc = Locale(locale ?: return null)
|
||||||
|
return lc.getDisplayLanguage(lc).toTitleCase(lc)
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package org.koitharu.kotatsu.core.parser
|
package org.koitharu.kotatsu.core.parser
|
||||||
|
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
import java.util.*
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.get
|
import org.koin.core.component.get
|
||||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||||
import org.koitharu.kotatsu.parsers.model.*
|
import org.koitharu.kotatsu.parsers.model.*
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
interface MangaRepository {
|
interface MangaRepository {
|
||||||
|
|
||||||
@@ -13,12 +13,9 @@ interface MangaRepository {
|
|||||||
|
|
||||||
val sortOrders: Set<SortOrder>
|
val sortOrders: Set<SortOrder>
|
||||||
|
|
||||||
suspend fun getList(
|
suspend fun getList(offset: Int, query: String?): List<Manga>
|
||||||
offset: Int,
|
|
||||||
query: String? = null,
|
suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga>
|
||||||
tags: Set<MangaTag>? = null,
|
|
||||||
sortOrder: SortOrder? = null,
|
|
||||||
): List<Manga>
|
|
||||||
|
|
||||||
suspend fun getDetails(manga: Manga): Manga
|
suspend fun getDetails(manga: Manga): Manga
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ class RemoteMangaRepository(private val parser: MangaParser) : MangaRepository {
|
|||||||
getConfig().defaultSortOrder = value
|
getConfig().defaultSortOrder = value
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getList(
|
override suspend fun getList(offset: Int, query: String?): List<Manga> {
|
||||||
offset: Int,
|
return parser.getList(offset, query)
|
||||||
query: String?,
|
}
|
||||||
tags: Set<MangaTag>?,
|
|
||||||
sortOrder: SortOrder?,
|
override suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> {
|
||||||
): List<Manga> = parser.getList(offset, query, tags, sortOrder)
|
return parser.getList(offset, tags, sortOrder)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getDetails(manga: Manga): Manga = parser.getDetails(manga)
|
override suspend fun getDetails(manga: Manga): Manga = parser.getDetails(manga)
|
||||||
|
|
||||||
|
|||||||
@@ -37,28 +37,25 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma
|
|||||||
private val filenameFilter = CbzFilter()
|
private val filenameFilter = CbzFilter()
|
||||||
private val locks = CompositeMutex<Long>()
|
private val locks = CompositeMutex<Long>()
|
||||||
|
|
||||||
override suspend fun getList(
|
override suspend fun getList(offset: Int, query: String?): List<Manga> {
|
||||||
offset: Int,
|
|
||||||
query: String?,
|
|
||||||
tags: Set<MangaTag>?,
|
|
||||||
sortOrder: SortOrder?
|
|
||||||
): List<Manga> {
|
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
val files = getAllFiles()
|
val list = getRawList()
|
||||||
val list = coroutineScope {
|
|
||||||
val dispatcher = Dispatchers.IO.limitedParallelism(MAX_PARALLELISM)
|
|
||||||
files.map { file ->
|
|
||||||
getFromFileAsync(file, dispatcher)
|
|
||||||
}.awaitAll()
|
|
||||||
}.filterNotNullTo(ArrayList(files.size))
|
|
||||||
if (!query.isNullOrEmpty()) {
|
if (!query.isNullOrEmpty()) {
|
||||||
list.retainAll { x ->
|
list.retainAll { x ->
|
||||||
x.title.contains(query, ignoreCase = true) ||
|
x.title.contains(query, ignoreCase = true) ||
|
||||||
x.altTitle?.contains(query, ignoreCase = true) == true
|
x.altTitle?.contains(query, ignoreCase = true) == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> {
|
||||||
|
if (offset > 0) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
val list = getRawList()
|
||||||
if (!tags.isNullOrEmpty()) {
|
if (!tags.isNullOrEmpty()) {
|
||||||
list.retainAll { x ->
|
list.retainAll { x ->
|
||||||
x.tags.containsAll(tags)
|
x.tags.containsAll(tags)
|
||||||
@@ -244,7 +241,7 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val sortOrders = emptySet<SortOrder>()
|
override val sortOrders = setOf(SortOrder.ALPHABETICAL)
|
||||||
|
|
||||||
override suspend fun getPageUrl(page: MangaPage) = page.url
|
override suspend fun getPageUrl(page: MangaPage) = page.url
|
||||||
|
|
||||||
@@ -295,6 +292,16 @@ class LocalMangaRepository(private val storageManager: LocalStorageManager) : Ma
|
|||||||
locks.unlock(id)
|
locks.unlock(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getRawList(): ArrayList<Manga> {
|
||||||
|
val files = getAllFiles()
|
||||||
|
return coroutineScope {
|
||||||
|
val dispatcher = Dispatchers.IO.limitedParallelism(MAX_PARALLELISM)
|
||||||
|
files.map { file ->
|
||||||
|
getFromFileAsync(file, dispatcher)
|
||||||
|
}.awaitAll()
|
||||||
|
}.filterNotNullTo(ArrayList(files.size))
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun getAllFiles() = storageManager.getReadableDirs().flatMap { dir ->
|
private suspend fun getAllFiles() = storageManager.getReadableDirs().flatMap { dir ->
|
||||||
dir.listFiles(filenameFilter)?.toList().orEmpty()
|
dir.listFiles(filenameFilter)?.toList().orEmpty()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.local.ui
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import java.io.IOException
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -24,6 +23,7 @@ import org.koitharu.kotatsu.utils.SingleLiveEvent
|
|||||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||||
import org.koitharu.kotatsu.utils.progress.Progress
|
import org.koitharu.kotatsu.utils.progress.Progress
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class LocalListViewModel(
|
class LocalListViewModel(
|
||||||
private val repository: LocalMangaRepository,
|
private val repository: LocalMangaRepository,
|
||||||
@@ -115,7 +115,7 @@ class LocalListViewModel(
|
|||||||
private suspend fun doRefresh() {
|
private suspend fun doRefresh() {
|
||||||
try {
|
try {
|
||||||
listError.value = null
|
listError.value = null
|
||||||
mangaList.value = repository.getList(0)
|
mangaList.value = repository.getList(0, null, null)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
listError.value = e
|
listError.value = e
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
|
|||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
|
||||||
import org.koitharu.kotatsu.parsers.util.levenshteinDistance
|
import org.koitharu.kotatsu.parsers.util.levenshteinDistance
|
||||||
import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider
|
import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ class MangaSearchRepository(
|
|||||||
MangaRepository(source).getList(
|
MangaRepository(source).getList(
|
||||||
offset = 0,
|
offset = 0,
|
||||||
query = query,
|
query = query,
|
||||||
sortOrder = SortOrder.POPULARITY
|
|
||||||
)
|
)
|
||||||
}.getOrElse {
|
}.getOrElse {
|
||||||
emptyList()
|
emptyList()
|
||||||
@@ -141,4 +139,4 @@ class MangaSearchRepository(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.settings.newsources
|
|||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.core.model.getLocaleTitle
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ class NewSourcesViewModel(
|
|||||||
sources.value = initialList.map {
|
sources.value = initialList.map {
|
||||||
SourceConfigItem.SourceItem(
|
SourceConfigItem.SourceItem(
|
||||||
source = it,
|
source = it,
|
||||||
summary = null,
|
summary = it.getLocaleTitle(),
|
||||||
isEnabled = it.name !in hidden,
|
isEnabled = it.name !in hidden,
|
||||||
isDraggable = false,
|
isDraggable = false,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import androidx.core.os.LocaleListCompat
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.core.model.getLocaleTitle
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||||
@@ -82,7 +83,7 @@ class SourcesSettingsViewModel(
|
|||||||
}
|
}
|
||||||
SourceConfigItem.SourceItem(
|
SourceConfigItem.SourceItem(
|
||||||
source = it,
|
source = it,
|
||||||
summary = null,
|
summary = it.getLocaleTitle(),
|
||||||
isEnabled = it.name !in hiddenSources,
|
isEnabled = it.name !in hiddenSources,
|
||||||
isDraggable = false,
|
isDraggable = false,
|
||||||
)
|
)
|
||||||
@@ -105,7 +106,7 @@ class SourcesSettingsViewModel(
|
|||||||
enabledSources.mapTo(result) {
|
enabledSources.mapTo(result) {
|
||||||
SourceConfigItem.SourceItem(
|
SourceConfigItem.SourceItem(
|
||||||
source = it,
|
source = it,
|
||||||
summary = getLocaleTitle(it.locale),
|
summary = it.getLocaleTitle(),
|
||||||
isEnabled = true,
|
isEnabled = true,
|
||||||
isDraggable = true,
|
isDraggable = true,
|
||||||
)
|
)
|
||||||
@@ -162,4 +163,4 @@ class SourcesSettingsViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,15 +17,17 @@ import org.koitharu.kotatsu.databinding.ItemSourceConfigBinding
|
|||||||
import org.koitharu.kotatsu.databinding.ItemSourceConfigDraggableBinding
|
import org.koitharu.kotatsu.databinding.ItemSourceConfigDraggableBinding
|
||||||
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||||
|
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
||||||
|
|
||||||
fun sourceConfigHeaderDelegate() = adapterDelegateViewBinding<SourceConfigItem.Header, SourceConfigItem, ItemFilterHeaderBinding>(
|
fun sourceConfigHeaderDelegate() =
|
||||||
{ layoutInflater, parent -> ItemFilterHeaderBinding.inflate(layoutInflater, parent, false) }
|
adapterDelegateViewBinding<SourceConfigItem.Header, SourceConfigItem, ItemFilterHeaderBinding>(
|
||||||
) {
|
{ layoutInflater, parent -> ItemFilterHeaderBinding.inflate(layoutInflater, parent, false) }
|
||||||
|
) {
|
||||||
|
|
||||||
bind {
|
bind {
|
||||||
binding.textViewTitle.setText(item.titleResId)
|
binding.textViewTitle.setText(item.titleResId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun sourceConfigGroupDelegate(
|
fun sourceConfigGroupDelegate(
|
||||||
listener: SourceConfigListener,
|
listener: SourceConfigListener,
|
||||||
@@ -61,6 +63,7 @@ fun sourceConfigItemDelegate(
|
|||||||
bind {
|
bind {
|
||||||
binding.textViewTitle.text = item.source.title
|
binding.textViewTitle.text = item.source.title
|
||||||
binding.switchToggle.isChecked = item.isEnabled
|
binding.switchToggle.isChecked = item.isEnabled
|
||||||
|
binding.textViewDescription.textAndVisible = item.summary
|
||||||
imageRequest = ImageRequest.Builder(context)
|
imageRequest = ImageRequest.Builder(context)
|
||||||
.data(item.faviconUrl)
|
.data(item.faviconUrl)
|
||||||
.error(R.drawable.ic_favicon_fallback)
|
.error(R.drawable.ic_favicon_fallback)
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:listPreferredItemHeightSmall"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="?android:listPreferredItemHeightSmall"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@@ -17,16 +18,35 @@
|
|||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/textView_title"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:layout_marginStart="?android:listPreferredItemPaddingStart"
|
||||||
|
android:layout_marginEnd="?android:listPreferredItemPaddingEnd"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:ellipsize="marquee"
|
android:orientation="vertical">
|
||||||
android:fadingEdge="horizontal"
|
|
||||||
android:singleLine="true"
|
<TextView
|
||||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
android:id="@+id/textView_title"
|
||||||
tools:text="@tools:sample/lorem[1]" />
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||||
|
tools:text="@tools:sample/lorem[15]" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||||
|
tools:text="English" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/switch_toggle"
|
android:id="@+id/switch_toggle"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/navigation_header"
|
android:id="@+id/navigation_header"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -16,7 +17,8 @@
|
|||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:contentDescription="@string/app_name"
|
android:contentDescription="@string/app_name"
|
||||||
android:src="@drawable/ic_totoro" />
|
android:src="@drawable/ic_totoro"
|
||||||
|
app:tint="?colorPrimary" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView_title"
|
android:id="@+id/textView_title"
|
||||||
|
|||||||
Reference in New Issue
Block a user