diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index fe4de5341..000000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -OpenManga Next \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5888471d0..f16d451de 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,19 +1,18 @@ - + android:theme="@style/AppTheme"> @@ -21,6 +20,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/repository/ReadmangaRepository.kt b/app/src/main/java/org/koitharu/kotatsu/domain/repository/ReadmangaRepository.kt index 43906e325..c6e637d23 100644 --- a/app/src/main/java/org/koitharu/kotatsu/domain/repository/ReadmangaRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/domain/repository/ReadmangaRepository.kt @@ -1,72 +1,90 @@ package org.koitharu.kotatsu.domain.repository +import androidx.core.text.HtmlCompat +import androidx.core.text.parseAsHtml import org.koitharu.kotatsu.core.model.* import org.koitharu.kotatsu.domain.MangaLoaderContext import org.koitharu.kotatsu.domain.MangaRepository import org.koitharu.kotatsu.domain.exceptions.ParseException -import org.koitharu.kotatsu.utils.ext.longHashCode -import org.koitharu.kotatsu.utils.ext.parseHtml -import org.koitharu.kotatsu.utils.ext.safe -import org.koitharu.kotatsu.utils.ext.withDomain +import org.koitharu.kotatsu.utils.ext.* class ReadmangaRepository(loaderContext: MangaLoaderContext) : MangaRepository(loaderContext) { - override suspend fun getList( - offset: Int, - query: String?, - sortOrder: SortOrder?, - tags: Set? - ): List { - val doc = loaderContext.get("https://readmanga.me/list?sortType=updated&offset=$offset") - .parseHtml() - val root = doc.body().getElementById("mangaBox") - ?.selectFirst("div.tiles.row") ?: throw ParseException("Cannot find root") - return root.select("div.tile").mapNotNull { node -> - val imgDiv = node.selectFirst("div.img") ?: return@mapNotNull null - val descDiv = node.selectFirst("div.desc") ?: return@mapNotNull null - val href = imgDiv.selectFirst("a").attr("href")?.withDomain("readmanga.me") - ?: return@mapNotNull null - val title = descDiv.selectFirst("h3")?.selectFirst("a")?.text() - ?: return@mapNotNull null - Manga( - id = href.longHashCode(), - url = href, - localizedTitle = title, - title = descDiv.selectFirst("h4")?.text() ?: title, - coverUrl = imgDiv.selectFirst("img.lazy")?.attr("data-original").orEmpty(), - summary = "", - rating = safe { - node.selectFirst("div.rating") - ?.attr("title") - ?.substringBefore(' ') - ?.toFloatOrNull() - ?.div(10f) - } ?: -1f, - tags = safe { - descDiv.selectFirst("div.tile-info") - ?.select("a.element-link") - ?.map { - MangaTag( - title = it.text(), - key = it.attr("href").substringAfterLast('/') - ) - }?.toSet() - }.orEmpty(), - state = when { - node.selectFirst("div.tags") - ?.selectFirst("span.mangaCompleted") != null -> MangaState.FINISHED - else -> null - }, - source = MangaSource.READMANGA_RU - ) - } - } + override suspend fun getList( + offset: Int, + query: String?, + sortOrder: SortOrder?, + tags: Set? + ): List { + val doc = loaderContext.get("https://readmanga.me/list?sortType=updated&offset=$offset") + .parseHtml() + val root = doc.body().getElementById("mangaBox") + ?.selectFirst("div.tiles.row") ?: throw ParseException("Cannot find root") + return root.select("div.tile").mapNotNull { node -> + val imgDiv = node.selectFirst("div.img") ?: return@mapNotNull null + val descDiv = node.selectFirst("div.desc") ?: return@mapNotNull null + val href = imgDiv.selectFirst("a").attr("href")?.withDomain("readmanga.me") + ?: return@mapNotNull null + val title = descDiv.selectFirst("h3")?.selectFirst("a")?.text() + ?: return@mapNotNull null + Manga( + id = href.longHashCode(), + url = href, + localizedTitle = title, + title = descDiv.selectFirst("h4")?.text() ?: title, + coverUrl = imgDiv.selectFirst("img.lazy")?.attr("data-original").orEmpty(), + summary = "", + rating = safe { + node.selectFirst("div.rating") + ?.attr("title") + ?.substringBefore(' ') + ?.toFloatOrNull() + ?.div(10f) + } ?: -1f, + tags = safe { + descDiv.selectFirst("div.tile-info") + ?.select("a.element-link") + ?.map { + MangaTag( + title = it.text(), + key = it.attr("href").substringAfterLast('/') + ) + }?.toSet() + }.orEmpty(), + state = when { + node.selectFirst("div.tags") + ?.selectFirst("span.mangaCompleted") != null -> MangaState.FINISHED + else -> null + }, + source = MangaSource.READMANGA_RU + ) + } + } - override suspend fun getDetails(manga: Manga): Manga { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } + override suspend fun getDetails(manga: Manga): Manga { + val doc = loaderContext.get(manga.url).parseHtml() + val root = doc.body().getElementById("mangaBox") + return manga.copy( + description = root.selectFirst("div.manga-description").firstChild()?.html()?.parseAsHtml(), + largeCoverUrl = root.selectFirst("div.subject-cower")?.selectFirst("img")?.attr( + "data-full" + ), + chapters = root.selectFirst("div.chapters-link")?.selectFirst("table") + ?.select("a")?.asReversed()?.mapIndexedNotNull { i, a -> + val href = + a.attr("href")?.withDomain("readmanga.me") ?: return@mapIndexedNotNull null + MangaChapter( + id = href.longHashCode(), + name = a.ownText(), + number = i + 1, + url = href, + source = MangaSource.READMANGA_RU + ) + } + ) + } - override suspend fun getPages(chapter: MangaChapter): List { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } + override suspend fun getPages(chapter: MangaChapter): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/ChipsFactory.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/ChipsFactory.kt new file mode 100644 index 000000000..b3ab5ad5b --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/ChipsFactory.kt @@ -0,0 +1,29 @@ +package org.koitharu.kotatsu.ui.common + +import android.content.Context +import android.graphics.drawable.Drawable +import android.view.View +import androidx.annotation.DrawableRes +import com.google.android.material.chip.Chip +import com.google.android.material.shape.CornerFamily +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.utils.ext.getThemeColor + +class ChipsFactory(private val context: Context) { + + fun create(convertView: Chip? = null, text: CharSequence, @DrawableRes iconRes: Int = 0, tag: Any? = null): Chip { + val chip = convertView ?: Chip(context).apply { + setTextColor(context.getThemeColor(android.R.attr.textColorPrimary)) + isCloseIconVisible = false + } + chip.text = text + if (iconRes == 0) { + chip.isChipIconVisible = false + } else { + chip.isCheckedIconVisible = true + chip.setChipIconResource(iconRes) + } + chip.tag = tag + return chip + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/RectFrameLayout.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/SquareLayout.kt similarity index 88% rename from app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/RectFrameLayout.kt rename to app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/SquareLayout.kt index c3079356d..33cbef26b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/RectFrameLayout.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/SquareLayout.kt @@ -4,7 +4,7 @@ import android.content.Context import android.util.AttributeSet import android.widget.FrameLayout -class RectFrameLayout @JvmOverloads constructor( +class SquareLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr) { diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChapterHolder.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChapterHolder.kt new file mode 100644 index 000000000..5e0f2b556 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChapterHolder.kt @@ -0,0 +1,15 @@ +package org.koitharu.kotatsu.ui.main.details + +import android.view.ViewGroup +import kotlinx.android.synthetic.main.item_chapter.* +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.model.MangaChapter +import org.koitharu.kotatsu.ui.common.list.BaseViewHolder + +class ChapterHolder(parent: ViewGroup) : BaseViewHolder(parent, R.layout.item_chapter) { + + override fun onBind(data: MangaChapter) { + textView_title.text = data.name + textView_number.text = data.number.toString() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChaptersAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChaptersAdapter.kt new file mode 100644 index 000000000..39e9a2965 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChaptersAdapter.kt @@ -0,0 +1,14 @@ +package org.koitharu.kotatsu.ui.main.details + +import android.view.ViewGroup +import org.koitharu.kotatsu.core.model.MangaChapter +import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter +import org.koitharu.kotatsu.ui.common.list.BaseViewHolder + +class ChaptersAdapter(onItemClickListener: ((MangaChapter) -> Unit)?) : + BaseRecyclerAdapter(onItemClickListener) { + + override fun onCreateViewHolder(parent: ViewGroup) = ChapterHolder(parent) + + override fun onGetItemId(item: MangaChapter) = item.id +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChaptersFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChaptersFragment.kt new file mode 100644 index 000000000..c08c665b4 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/ChaptersFragment.kt @@ -0,0 +1,40 @@ +package org.koitharu.kotatsu.ui.main.details + +import android.os.Bundle +import android.view.View +import androidx.core.view.isVisible +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.fragment_chapters.* +import moxy.ktx.moxyPresenter +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.ui.common.BaseFragment + +class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsView { + + private val presenter by moxyPresenter { (activity as MangaDetailsActivity).presenter } + + private lateinit var adapter: ChaptersAdapter + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + adapter = ChaptersAdapter { + + } + recyclerView_chapters.addItemDecoration(DividerItemDecoration(view.context, RecyclerView.VERTICAL)) + recyclerView_chapters.adapter = adapter + } + + override fun onMangaUpdated(manga: Manga) { + adapter.replaceData(manga.chapters.orEmpty()) + } + + override fun onLoadingStateChanged(isLoading: Boolean) { + progressBar.isVisible = isLoading + } + + override fun onError(e: Exception) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsActivity.kt new file mode 100644 index 000000000..f11fb4df1 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsActivity.kt @@ -0,0 +1,48 @@ +package org.koitharu.kotatsu.ui.main.details + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.viewpager.widget.ViewPager +import com.google.android.material.snackbar.Snackbar +import com.google.android.material.tabs.TabLayout +import kotlinx.android.synthetic.main.activity_details.* +import moxy.ktx.moxyPresenter +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.ui.common.BaseActivity +import org.koitharu.kotatsu.utils.ext.getDisplayMessage + +class MangaDetailsActivity : BaseActivity(), MangaDetailsView { + + val presenter by moxyPresenter(factory = ::MangaDetailsPresenter) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_details) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + pager.adapter = MangaDetailsAdapter(resources, supportFragmentManager) + tabs.setupWithViewPager(pager) + intent?.getParcelableExtra(EXTRA_MANGA)?.let { + presenter.loadDetails(it) + } ?: finish() + } + + override fun onMangaUpdated(manga: Manga) { + title = manga.title + } + + override fun onLoadingStateChanged(isLoading: Boolean) = Unit + + override fun onError(e: Exception) { + Snackbar.make(pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show() + } + + companion object { + + private const val EXTRA_MANGA = "manga" + + fun newIntent(context: Context, manga: Manga) = Intent(context, MangaDetailsActivity::class.java) + .putExtra(EXTRA_MANGA, manga) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsAdapter.kt new file mode 100644 index 000000000..087a68fb0 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsAdapter.kt @@ -0,0 +1,25 @@ +package org.koitharu.kotatsu.ui.main.details + +import android.content.res.Resources +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter +import androidx.viewpager2.adapter.FragmentStateAdapter +import org.koitharu.kotatsu.R + +class MangaDetailsAdapter(private val resources: Resources, fm: FragmentManager) : FragmentPagerAdapter(fm, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + + override fun getCount() = 2 + + override fun getItem(position: Int): Fragment = when(position) { + 0 -> MangaDetailsFragment() + 1 -> ChaptersFragment() + else -> throw IndexOutOfBoundsException("No fragment for position $position") + } + + override fun getPageTitle(position: Int): CharSequence? = when(position) { + 0 -> resources.getString(R.string.details) + 1 -> resources.getString(R.string.chapters) + else -> null + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsFragment.kt new file mode 100644 index 000000000..584913a2b --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsFragment.kt @@ -0,0 +1,43 @@ +package org.koitharu.kotatsu.ui.main.details + +import android.os.Bundle +import androidx.core.view.isVisible +import coil.api.load +import kotlinx.android.synthetic.main.fragment_details.* +import moxy.ktx.moxyPresenter +import org.koin.core.get +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.ui.common.BaseFragment +import org.koitharu.kotatsu.utils.ext.setChips + +class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetailsView { + + private val presenter by moxyPresenter { (activity as MangaDetailsActivity).presenter } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + } + + override fun onMangaUpdated(manga: Manga) { + imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl) + textView_title.text = manga.title + textView_subtitle.text = manga.localizedTitle + textView_description.text = manga.description + chips_tags.setChips(manga.tags) { + create( + text = it.title, + iconRes = R.drawable.ic_chip_tag, + tag = it + ) + } + } + + override fun onLoadingStateChanged(isLoading: Boolean) { + progressBar.isVisible = isLoading + } + + override fun onError(e: Exception) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsPresenter.kt new file mode 100644 index 000000000..a72a6cbbc --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsPresenter.kt @@ -0,0 +1,40 @@ +package org.koitharu.kotatsu.ui.main.details + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import moxy.InjectViewState +import org.koitharu.kotatsu.BuildConfig +import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.domain.MangaProviderFactory +import org.koitharu.kotatsu.ui.common.BasePresenter + +@InjectViewState +class MangaDetailsPresenter : BasePresenter() { + + private var isLoaded = false + + fun loadDetails(manga: Manga) { + if (isLoaded) { + return + } + viewState.onMangaUpdated(manga) + launch { + try { + viewState.onLoadingStateChanged(true) + val details = withContext(Dispatchers.IO) { + MangaProviderFactory.create(manga.source).getDetails(manga) + } + viewState.onMangaUpdated(details) + isLoaded = true + } catch (e: Exception) { + if (BuildConfig.DEBUG) { + e.printStackTrace() + } + viewState.onError(e) + } finally { + viewState.onLoadingStateChanged(false) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsView.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsView.kt new file mode 100644 index 000000000..bf3f9aa3e --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/details/MangaDetailsView.kt @@ -0,0 +1,19 @@ +package org.koitharu.kotatsu.ui.main.details + +import moxy.MvpView +import moxy.viewstate.strategy.AddToEndSingleStrategy +import moxy.viewstate.strategy.OneExecutionStateStrategy +import moxy.viewstate.strategy.StateStrategyType +import org.koitharu.kotatsu.core.model.Manga + +interface MangaDetailsView : MvpView { + + @StateStrategyType(AddToEndSingleStrategy::class) + fun onMangaUpdated(manga: Manga) + + @StateStrategyType(AddToEndSingleStrategy::class) + fun onLoadingStateChanged(isLoading: Boolean) + + @StateStrategyType(OneExecutionStateStrategy::class) + fun onError(e: Exception) +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt index 98422ce6f..3e874a027 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt @@ -14,6 +14,7 @@ import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.ui.common.BaseFragment import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener import org.koitharu.kotatsu.ui.common.list.SpacingItemDecoration +import org.koitharu.kotatsu.ui.main.details.MangaDetailsActivity import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.hasItems import org.koitharu.kotatsu.utils.ext.withArgs @@ -30,7 +31,7 @@ class MangaListFragment : BaseFragment(R.layout.fragment_list), MangaListView, override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) adapter = MangaListAdapter { - + startActivity(MangaDetailsActivity.newIntent(context ?: return@MangaListAdapter, it)) } // recyclerView.addItemDecoration(SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))) recyclerView.addItemDecoration(DividerItemDecoration(view.context, RecyclerView.VERTICAL)) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/JsoupExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/JsoupExt.kt index 474e8e682..75e3eada3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/JsoupExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/JsoupExt.kt @@ -4,6 +4,7 @@ import okhttp3.Response import okhttp3.internal.closeQuietly import org.jsoup.Jsoup import org.jsoup.nodes.Document +import org.jsoup.nodes.Element fun Response.parseHtml(): Document { val stream = body?.byteStream() ?: throw NullPointerException("Response body is null") @@ -15,4 +16,6 @@ fun Response.parseHtml(): Document { ) closeQuietly() return doc -} \ No newline at end of file +} + +fun Element.firstChild(): Element? = children().first() \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/StringExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/StringExt.kt index 91f4b285a..ba7c82545 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/StringExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/StringExt.kt @@ -9,7 +9,15 @@ fun String.longHashCode(): Long { return h } -fun String.withDomain(domain: String) = when { - this.startsWith("/") -> "http://$domain" +fun String.withDomain(domain: String, ssl: Boolean = true) = when { + this.startsWith("/") -> buildString { + append("http") + if (ssl) { + append('s') + } + append("://") + append(domain) + append(this@withDomain) + } else -> this } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt index 1a46b2bc9..70e8decbf 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt @@ -13,6 +13,9 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.chip.Chip +import com.google.android.material.chip.ChipGroup +import org.koitharu.kotatsu.ui.common.ChipsFactory fun View.hideKeyboard() { val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager @@ -61,4 +64,13 @@ var TextView.textAndVisible: CharSequence? set(value) { text = value isGone = value.isNullOrEmpty() - } \ No newline at end of file + } + +fun ChipGroup.setChips(data: Iterable, action: ChipsFactory.(T) -> Chip) { + removeAllViews() + val factory = ChipsFactory(context) + data.forEach { + val chip = factory.action(it) + addView(chip) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_round_rect.xml b/app/src/main/res/drawable/bg_round_rect.xml new file mode 100644 index 000000000..847a0497b --- /dev/null +++ b/app/src/main/res/drawable/bg_round_rect.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_chip_tag.xml b/app/src/main/res/drawable/ic_chip_tag.xml new file mode 100644 index 000000000..d5df0cdda --- /dev/null +++ b/app/src/main/res/drawable/ic_chip_tag.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml index b500514ae..2cc05a897 100644 --- a/app/src/main/res/drawable/ic_history.xml +++ b/app/src/main/res/drawable/ic_history.xml @@ -1,10 +1,10 @@ - + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 000000000..d58e21c11 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_star_half.xml b/app/src/main/res/drawable/ic_star_half.xml index 4be9bf32c..463042243 100644 --- a/app/src/main/res/drawable/ic_star_half.xml +++ b/app/src/main/res/drawable/ic_star_half.xml @@ -1,14 +1,14 @@ - - - - + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + + + + diff --git a/app/src/main/res/drawable/ic_storage.xml b/app/src/main/res/drawable/ic_storage.xml index bf3fc357c..622253195 100644 --- a/app/src/main/res/drawable/ic_storage.xml +++ b/app/src/main/res/drawable/ic_storage.xml @@ -1,10 +1,10 @@ - + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + diff --git a/app/src/main/res/layout/activity_details.xml b/app/src/main/res/layout/activity_details.xml new file mode 100644 index 000000000..25370ec6e --- /dev/null +++ b/app/src/main/res/layout/activity_details.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_chapters.xml b/app/src/main/res/layout/fragment_chapters.xml new file mode 100644 index 000000000..98874732e --- /dev/null +++ b/app/src/main/res/layout/fragment_chapters.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml new file mode 100644 index 000000000..cdc0cca09 --- /dev/null +++ b/app/src/main/res/layout/fragment_details.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_chapter.xml b/app/src/main/res/layout/item_chapter.xml new file mode 100644 index 000000000..5986d1bcb --- /dev/null +++ b/app/src/main/res/layout/item_chapter.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_manga_list.xml b/app/src/main/res/layout/item_manga_list.xml index ba78c829d..2f63b793b 100644 --- a/app/src/main/res/layout/item_manga_list.xml +++ b/app/src/main/res/layout/item_manga_list.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 42ed64e5f..9c088013c 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,5 +1,6 @@ 5dp - 84dp + 84dp + 46dp \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 87d77b1e7..af4c3e7eb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,4 +7,6 @@ History An error has occurred Network connection error + Details + Chapters \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index b4a529bf6..2fba1a29b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ include ':app' -rootProject.name = "OpenManga Next" \ No newline at end of file +rootProject.name = "Kotatsu" \ No newline at end of file