mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 11:51:50 +01:00
Tracker improvements (#473)
* add tracker logout dialog from upstream * update for all trackers to have logout dialog * remove logout button from login screen * new login button that is more material had to remove red_error color cause that was in the library that i removed * return error message if user has blank username/password * add x button to clear tracked Manga add dialog that gives option to clear just in app or from tracking service added mal as first service to allow clearing * fix string in dialog for remove ad ability to remove from anilist service * add ability to delete from kitsu * made login dialog look more material * change the dialog for the remove from tracker * update coil to 0.11.0 * make track search a little nicer
This commit is contained in:
parent
585e57c8bf
commit
442a439e66
@ -196,7 +196,7 @@ dependencies {
|
||||
|
||||
// UI
|
||||
implementation("com.dmitrymalkovich.android:material-design-dimens:1.4")
|
||||
implementation("com.github.dmytrodanylyk.android-process-button:library:1.0.4")
|
||||
implementation("br.com.simplepass:loading-button-android:2.2.0")
|
||||
implementation("com.mikepenz:fastadapter:${Versions.FASTADAPTER}")
|
||||
implementation("com.mikepenz:fastadapter-extensions-binding:${Versions.FASTADAPTER}")
|
||||
implementation("eu.davidea:flexible-adapter:5.1.0")
|
||||
|
@ -13,7 +13,7 @@ abstract class TrackService(val id: Int) {
|
||||
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
val networkService: NetworkHelper by injectLazy()
|
||||
|
||||
open fun canRemoveFromService() = false
|
||||
open val client: OkHttpClient
|
||||
get() = networkService.client
|
||||
|
||||
@ -51,6 +51,8 @@ abstract class TrackService(val id: Int) {
|
||||
|
||||
abstract suspend fun login(username: String, password: String): Boolean
|
||||
|
||||
open suspend fun removeFromService(track: Track): Boolean = false
|
||||
|
||||
@CallSuper
|
||||
open fun logout() {
|
||||
preferences.setTrackCredentials(this, "", "")
|
||||
|
@ -150,6 +150,12 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canRemoveFromService(): Boolean = true
|
||||
|
||||
override suspend fun removeFromService(track: Track): Boolean {
|
||||
return api.remove(track)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String) = api.search(query)
|
||||
|
||||
override suspend fun refresh(track: Track): Track {
|
||||
|
@ -19,6 +19,7 @@ import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import timber.log.Timber
|
||||
import java.util.Calendar
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@ -128,6 +129,29 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun remove(track: Track): Boolean {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
|
||||
val variables = jsonObject(
|
||||
"listId" to track.library_id
|
||||
)
|
||||
val payload = jsonObject(
|
||||
"query" to deleteFromLibraryQuery(),
|
||||
"variables" to variables
|
||||
)
|
||||
|
||||
val body = payload.toString().toRequestBody(MediaType.jsonType())
|
||||
val request = Request.Builder().url(apiUrl).post(body).build()
|
||||
val result = authClient.newCall(request).execute()
|
||||
return@withContext true
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e)
|
||||
}
|
||||
return@withContext false
|
||||
}
|
||||
}
|
||||
|
||||
fun createOAuth(token: String): OAuth {
|
||||
return OAuth(
|
||||
token,
|
||||
@ -222,6 +246,14 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
|
||||
fun deleteFromLibraryQuery() = """
|
||||
|mutation DeleteManga(${'$'}listId: Int) {
|
||||
|DeleteMediaListEntry (id: ${'$'}listId) {
|
||||
|deleted
|
||||
|
||||
|}
|
||||
|}""".trimMargin()
|
||||
|
||||
fun updateInLibraryQuery() = """
|
||||
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
|
||||
|SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) {
|
||||
|
@ -103,6 +103,12 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canRemoveFromService() = true
|
||||
|
||||
override suspend fun removeFromService(track: Track): Boolean {
|
||||
return api.remove(track)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<TrackSearch> {
|
||||
return api.search(query)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.DELETE
|
||||
import retrofit2.http.Field
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.GET
|
||||
@ -25,6 +26,7 @@ import retrofit2.http.PATCH
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
import timber.log.Timber
|
||||
|
||||
class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) {
|
||||
|
||||
@ -97,6 +99,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
return track
|
||||
}
|
||||
|
||||
suspend fun remove(track: Track): Boolean {
|
||||
try {
|
||||
rest.deleteLibManga(track.media_id)
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
suspend fun search(query: String): List<TrackSearch> {
|
||||
val key = searchRest.getKey()["media"].asJsonObject["key"].string
|
||||
return algoliaSearch(key, query)
|
||||
@ -156,6 +168,12 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
@Body data: JsonObject
|
||||
): JsonObject
|
||||
|
||||
@Headers("Content-Type: application/vnd.api+json")
|
||||
@DELETE("library-entries/{id}")
|
||||
suspend fun deleteLibManga(
|
||||
@Path("id") remoteId: Int
|
||||
): JsonObject
|
||||
|
||||
@Headers("Content-Type: application/vnd.api+json")
|
||||
@PATCH("library-entries/{id}")
|
||||
suspend fun updateLibManga(
|
||||
|
@ -79,6 +79,12 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
||||
return track
|
||||
}
|
||||
|
||||
override fun canRemoveFromService(): Boolean = true
|
||||
|
||||
override suspend fun removeFromService(track: Track): Boolean {
|
||||
return api.remove(track)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<TrackSearch> {
|
||||
return api.search(query)
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.parser.Parser
|
||||
import timber.log.Timber
|
||||
|
||||
class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) {
|
||||
|
||||
@ -40,18 +41,18 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
.select("tbody").select("tr").drop(1)
|
||||
|
||||
matches.filter { row -> row.select(TD)[2].text() != "Novel" }.map { row ->
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = row.searchTitle()
|
||||
media_id = row.searchMediaId()
|
||||
total_chapters = row.searchTotalChapters()
|
||||
summary = row.searchSummary()
|
||||
cover_url = row.searchCoverUrl()
|
||||
tracking_url = mangaUrl(media_id)
|
||||
publishing_status = row.searchPublishingStatus()
|
||||
publishing_type = row.searchPublishingType()
|
||||
start_date = row.searchStartDate()
|
||||
}
|
||||
}.toList()
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = row.searchTitle()
|
||||
media_id = row.searchMediaId()
|
||||
total_chapters = row.searchTotalChapters()
|
||||
summary = row.searchSummary()
|
||||
cover_url = row.searchCoverUrl()
|
||||
tracking_url = mangaUrl(media_id)
|
||||
publishing_status = row.searchPublishingStatus()
|
||||
publishing_type = row.searchPublishingType()
|
||||
start_date = row.searchStartDate()
|
||||
}
|
||||
}.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,6 +72,16 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
return track
|
||||
}
|
||||
|
||||
suspend fun remove(track: Track): Boolean {
|
||||
try {
|
||||
authClient.newCall(POST(url = removeUrl(track.media_id))).await()
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
suspend fun findLibManga(track: Track): Track? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val response = authClient.newCall(GET(url = listEntryUrl(track.media_id))).await()
|
||||
@ -133,16 +144,16 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
val results = getListXml(getListUrl()).select("manga")
|
||||
|
||||
return results.map {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("manga_title")!!
|
||||
media_id = it.selectInt("manga_mangadb_id")
|
||||
last_chapter_read = it.selectInt("my_read_chapters")
|
||||
status = getStatus(it.selectText("my_status")!!)
|
||||
score = it.selectInt("my_score").toFloat()
|
||||
total_chapters = it.selectInt("manga_chapters")
|
||||
tracking_url = mangaUrl(media_id)
|
||||
}
|
||||
}.toList()
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("manga_title")!!
|
||||
media_id = it.selectInt("manga_mangadb_id")
|
||||
last_chapter_read = it.selectInt("my_read_chapters")
|
||||
status = getStatus(it.selectText("my_status")!!)
|
||||
score = it.selectInt("my_score").toFloat()
|
||||
total_chapters = it.selectInt("manga_chapters")
|
||||
tracking_url = mangaUrl(media_id)
|
||||
}
|
||||
}.toList()
|
||||
}
|
||||
|
||||
private suspend fun getListUrl(): String {
|
||||
@ -188,6 +199,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
private fun updateUrl() =
|
||||
Uri.parse(baseModifyListUrl).buildUpon().appendPath("edit.json").toString()
|
||||
|
||||
private fun removeUrl(mediaId: Int) = Uri.parse(baseModifyListUrl).buildUpon().appendPath(mediaId.toString())
|
||||
.appendPath("delete").toString()
|
||||
|
||||
private fun addUrl() =
|
||||
Uri.parse(baseModifyListUrl).buildUpon().appendPath("add.json").toString()
|
||||
|
||||
|
@ -24,7 +24,7 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
private val downloadedColor = ContextCompat.getColor(context,
|
||||
R.color.download)
|
||||
private val errorColor = ContextCompat.getColor(context,
|
||||
R.color.red_error)
|
||||
R.color.material_red_500)
|
||||
private val filledCircle = ContextCompat.getDrawable(context,
|
||||
R.drawable.filled_circle)?.mutate()
|
||||
private val borderCircle = ContextCompat.getDrawable(context,
|
||||
|
@ -850,13 +850,18 @@ class MangaDetailsPresenter(
|
||||
}
|
||||
fetchTracks()
|
||||
}
|
||||
} else {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
db.deleteTrackForManga(manga, service).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeTracker(trackItem: TrackItem, removeFromService: Boolean) {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
db.deleteTrackForManga(manga, trackItem.service).executeAsBlocking()
|
||||
if (removeFromService && trackItem.service.canRemoveFromService()) {
|
||||
trackItem.service.removeFromService(trackItem.track!!)
|
||||
}
|
||||
fetchTracks()
|
||||
}
|
||||
fetchTracks()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,5 +45,6 @@ class TrackAdapter(controller: OnClickListener) : RecyclerView.Adapter<TrackHold
|
||||
fun onStatusClick(position: Int)
|
||||
fun onChaptersClick(position: Int)
|
||||
fun onScoreClick(position: Int)
|
||||
fun onRemoveClick(position: Int)
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) {
|
||||
logo_container.setOnClickListener { listener.onLogoClick(adapterPosition) }
|
||||
add_tracking.setOnClickListener { listener.onSetClick(adapterPosition) }
|
||||
track_title.setOnClickListener { listener.onSetClick(adapterPosition) }
|
||||
track_remove.setOnClickListener { listener.onRemoveClick(adapterPosition) }
|
||||
track_status.setOnClickListener { listener.onStatusClick(adapterPosition) }
|
||||
track_chapters.setOnClickListener { listener.onChaptersClick(adapterPosition) }
|
||||
score_container.setOnClickListener { listener.onScoreClick(adapterPosition) }
|
||||
|
@ -0,0 +1,64 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.track
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.checkbox.checkBoxPrompt
|
||||
import com.afollestad.materialdialogs.checkbox.getCheckBoxPrompt
|
||||
import com.afollestad.materialdialogs.checkbox.isCheckPromptChecked
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class TrackRemoveDialog<T> : DialogController
|
||||
where T : TrackRemoveDialog.Listener {
|
||||
|
||||
private val item: TrackItem
|
||||
private lateinit var listener: Listener
|
||||
|
||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||
}) {
|
||||
listener = target
|
||||
this.item = item
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(bundle: Bundle) : super(bundle) {
|
||||
val track = bundle.getSerializable(KEY_ITEM_TRACK) as Track
|
||||
val service = Injekt.get<TrackManager>().getService(track.sync_id)!!
|
||||
item = TrackItem(track, service)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val item = item
|
||||
|
||||
val dialog = MaterialDialog(activity!!)
|
||||
.title(R.string.remove_tracking)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
|
||||
if (item.service.canRemoveFromService()) {
|
||||
dialog.checkBoxPrompt(
|
||||
text = activity!!.getString(
|
||||
R.string.remove_tracking_from_, item.service.name
|
||||
), onToggle = null
|
||||
).positiveButton(android.R.string.ok) { listener.removeTracker(item, it.isCheckPromptChecked()) }
|
||||
dialog.getCheckBoxPrompt().textSize = 16f
|
||||
} else {
|
||||
dialog.positiveButton(android.R.string.ok) { listener.removeTracker(item, false) }
|
||||
}
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun removeTracker(item: TrackItem, fromServiceAlso: Boolean)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val KEY_ITEM_TRACK = "TrackRemoveDialog.item.track"
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ class TrackSearchDialog : DialogController {
|
||||
private lateinit var bottomSheet: TrackingBottomSheet
|
||||
|
||||
private var wasPreviouslyTracked: Boolean = false
|
||||
|
||||
private lateinit var presenter: MangaDetailsPresenter
|
||||
|
||||
constructor(target: TrackingBottomSheet, service: TrackService, wasTracked: Boolean) : super(Bundle()
|
||||
@ -61,9 +62,6 @@ class TrackSearchDialog : DialogController {
|
||||
val dialog = MaterialDialog(activity!!).apply {
|
||||
customView(viewRes = R.layout.track_search_dialog, scrollable = false)
|
||||
negativeButton(android.R.string.cancel)
|
||||
if (wasPreviouslyTracked) {
|
||||
positiveButton(R.string.clear) { onPositiveButtonClick() }
|
||||
}
|
||||
}
|
||||
|
||||
if (subscriptions.isUnsubscribed) {
|
||||
@ -151,12 +149,6 @@ class TrackSearchDialog : DialogController {
|
||||
adapter?.setItems(emptyList())
|
||||
}
|
||||
|
||||
private fun onPositiveButtonClick() {
|
||||
bottomSheet.refreshTrack(service)
|
||||
presenter.registerTracking(null,
|
||||
service)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val KEY_SERVICE = "service_id"
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
||||
TrackAdapter.OnClickListener,
|
||||
SetTrackStatusDialog.Listener,
|
||||
SetTrackChaptersDialog.Listener,
|
||||
SetTrackScoreDialog.Listener {
|
||||
SetTrackScoreDialog.Listener,
|
||||
TrackRemoveDialog.Listener {
|
||||
|
||||
val activity = controller.activity!!
|
||||
|
||||
@ -145,6 +146,18 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
||||
SetTrackStatusDialog(this, item).showDialog(controller.router)
|
||||
}
|
||||
|
||||
override fun onRemoveClick(position: Int) {
|
||||
val item = adapter?.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
|
||||
if (controller.isNotOnline()) {
|
||||
dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
TrackRemoveDialog(this, item).showDialog(controller.router)
|
||||
}
|
||||
|
||||
override fun onChaptersClick(position: Int) {
|
||||
val item = adapter?.getItem(position) ?: return
|
||||
if (item.track == null) return
|
||||
@ -197,6 +210,11 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
||||
refreshItem(item)
|
||||
}
|
||||
|
||||
override fun removeTracker(item: TrackItem, fromServiceAlso: Boolean) {
|
||||
refreshTrack(item.service)
|
||||
presenter.removeTracker(item, fromServiceAlso)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TAG_SEARCH_CONTROLLER = "track_search_controller"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
@ -13,11 +14,12 @@ import eu.kanade.tachiyomi.data.track.shikimori.ShikimoriApi
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.widget.preference.LoginPreference
|
||||
import eu.kanade.tachiyomi.widget.preference.TrackLoginDialog
|
||||
import eu.kanade.tachiyomi.widget.preference.TrackLogoutDialog
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
class SettingsTrackingController : SettingsController(),
|
||||
TrackLoginDialog.Listener {
|
||||
TrackLoginDialog.Listener, TrackLogoutDialog.Listener {
|
||||
|
||||
private val trackManager: TrackManager by injectLazy()
|
||||
|
||||
@ -34,43 +36,27 @@ class SettingsTrackingController : SettingsController(),
|
||||
|
||||
trackPreference(trackManager.myAnimeList) {
|
||||
onClick {
|
||||
val dialog = TrackLoginDialog(trackManager.myAnimeList)
|
||||
dialog.targetController = this@SettingsTrackingController
|
||||
dialog.showDialog(router)
|
||||
showDialog(trackManager.myAnimeList)
|
||||
}
|
||||
}
|
||||
trackPreference(trackManager.aniList) {
|
||||
onClick {
|
||||
val tabsIntent = CustomTabsIntent.Builder()
|
||||
.setToolbarColor(context.getResourceColor(R.attr.colorPrimaryVariant))
|
||||
.build()
|
||||
tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
||||
tabsIntent.launchUrl(activity!!, AnilistApi.authUrl())
|
||||
showDialog(trackManager.aniList, AnilistApi.authUrl())
|
||||
}
|
||||
}
|
||||
trackPreference(trackManager.kitsu) {
|
||||
onClick {
|
||||
val dialog = TrackLoginDialog(trackManager.kitsu, context.getString(R.string.email))
|
||||
dialog.targetController = this@SettingsTrackingController
|
||||
dialog.showDialog(router)
|
||||
showDialog(trackManager.kitsu, userNameLabel = context.getString(R.string.email))
|
||||
}
|
||||
}
|
||||
trackPreference(trackManager.shikimori) {
|
||||
onClick {
|
||||
val tabsIntent = CustomTabsIntent.Builder()
|
||||
.setToolbarColor(context.getResourceColor(R.attr.colorPrimaryVariant))
|
||||
.build()
|
||||
tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
||||
tabsIntent.launchUrl(activity!!, ShikimoriApi.authUrl())
|
||||
showDialog(trackManager.shikimori, ShikimoriApi.authUrl())
|
||||
}
|
||||
}
|
||||
trackPreference(trackManager.bangumi) {
|
||||
onClick {
|
||||
val tabsIntent = CustomTabsIntent.Builder()
|
||||
.setToolbarColor(context.getResourceColor(R.attr.colorPrimaryVariant))
|
||||
.build()
|
||||
tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
||||
tabsIntent.launchUrl(activity!!, BangumiApi.authUrl())
|
||||
showDialog(trackManager.bangumi, BangumiApi.authUrl())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,6 +77,25 @@ class SettingsTrackingController : SettingsController(),
|
||||
// Manually refresh anilist holder
|
||||
updatePreference(trackManager.aniList.id)
|
||||
updatePreference(trackManager.shikimori.id)
|
||||
updatePreference(trackManager.bangumi.id)
|
||||
}
|
||||
|
||||
private fun showDialog(trackService: TrackService, url: Uri? = null, userNameLabel: String? = null) {
|
||||
if (trackService.isLogged) {
|
||||
val dialog = TrackLogoutDialog(trackService)
|
||||
dialog.targetController = this@SettingsTrackingController
|
||||
dialog.showDialog(router)
|
||||
} else if (url == null) {
|
||||
val dialog = TrackLoginDialog(trackService, userNameLabel)
|
||||
dialog.targetController = this@SettingsTrackingController
|
||||
dialog.showDialog(router)
|
||||
} else {
|
||||
val tabsIntent = CustomTabsIntent.Builder()
|
||||
.setToolbarColor(activity!!.getResourceColor(R.attr.colorPrimaryVariant))
|
||||
.build()
|
||||
tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
||||
tabsIntent.launchUrl(activity!!, url)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePreference(id: Int) {
|
||||
@ -98,7 +103,11 @@ class SettingsTrackingController : SettingsController(),
|
||||
pref?.notifyChanged()
|
||||
}
|
||||
|
||||
override fun trackDialogClosed(service: TrackService) {
|
||||
override fun trackLoginDialogClosed(service: TrackService) {
|
||||
updatePreference(service.id)
|
||||
}
|
||||
|
||||
override fun trackLogoutDialogClosed(service: TrackService) {
|
||||
updatePreference(service.id)
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,14 @@ package eu.kanade.tachiyomi.widget.preference
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.text.method.PasswordTransformationMethod
|
||||
import android.view.View
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.dd.processbutton.iml.ActionProcessButton
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.view.visible
|
||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -42,7 +38,6 @@ abstract class LoginDialogPreference(
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
val dialog = MaterialDialog(activity!!).apply {
|
||||
customView(R.layout.pref_account_login, scrollable = false)
|
||||
positiveButton(android.R.string.cancel)
|
||||
}
|
||||
|
||||
onViewCreated(dialog.view)
|
||||
@ -50,40 +45,18 @@ abstract class LoginDialogPreference(
|
||||
return dialog
|
||||
}
|
||||
|
||||
open fun logout() {}
|
||||
|
||||
fun onViewCreated(view: View) {
|
||||
v = view.apply {
|
||||
show_password.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked)
|
||||
password.transformationMethod = null
|
||||
else
|
||||
password.transformationMethod = PasswordTransformationMethod()
|
||||
}
|
||||
|
||||
if (!usernameLabel.isNullOrEmpty()) {
|
||||
username_label.text = usernameLabel
|
||||
username_input.hint = usernameLabel
|
||||
}
|
||||
|
||||
login.setMode(ActionProcessButton.Mode.ENDLESS)
|
||||
login.setOnClickListener { checkLogin() }
|
||||
login.setOnClickListener {
|
||||
checkLogin()
|
||||
}
|
||||
|
||||
setCredentialsOnView(this)
|
||||
|
||||
if (canLogout && !username.text.isNullOrEmpty()) {
|
||||
logout.visible()
|
||||
logout.setOnClickListener { logout() }
|
||||
}
|
||||
|
||||
show_password.isEnabled = password.text.isNullOrEmpty()
|
||||
|
||||
password.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
if (s.isEmpty()) {
|
||||
show_password.isEnabled = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.widget.preference
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import br.com.simplepass.loadingbutton.animatedDrawables.ProgressType
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
@ -18,8 +19,6 @@ class TrackLoginDialog(usernameLabel: String? = null, bundle: Bundle? = null) :
|
||||
|
||||
override var canLogout = true
|
||||
|
||||
constructor(service: TrackService) : this(service, null)
|
||||
|
||||
constructor(service: TrackService, usernameLabel: String?) :
|
||||
this(usernameLabel, Bundle().apply { putInt("key", service.id) })
|
||||
|
||||
@ -32,13 +31,18 @@ class TrackLoginDialog(usernameLabel: String? = null, bundle: Bundle? = null) :
|
||||
override fun checkLogin() {
|
||||
|
||||
v?.apply {
|
||||
if (username.text.isEmpty() || password.text.isEmpty())
|
||||
login.apply {
|
||||
progressType = ProgressType.INDETERMINATE
|
||||
startAnimation()
|
||||
}
|
||||
if (username.text.isNullOrBlank() || password.text.isNullOrBlank()) {
|
||||
errorResult()
|
||||
context.toast(R.string.username_must_not_be_blank)
|
||||
return
|
||||
}
|
||||
|
||||
login.progress = 1
|
||||
val user = username.text.toString()
|
||||
val pass = password.text.toString()
|
||||
|
||||
scope.launch {
|
||||
try {
|
||||
val result = service.login(user, pass)
|
||||
@ -58,24 +62,18 @@ class TrackLoginDialog(usernameLabel: String? = null, bundle: Bundle? = null) :
|
||||
|
||||
private fun errorResult() {
|
||||
v?.apply {
|
||||
login.progress = -1
|
||||
login.setText(R.string.unknown_error)
|
||||
}
|
||||
}
|
||||
|
||||
override fun logout() {
|
||||
if (service.isLogged) {
|
||||
service.logout()
|
||||
activity?.toast(R.string.successfully_logged_out)
|
||||
login.revertAnimation {
|
||||
login.text = activity!!.getText(R.string.unknown_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDialogClosed() {
|
||||
super.onDialogClosed()
|
||||
(targetController as? Listener)?.trackDialogClosed(service)
|
||||
(targetController as? Listener)?.trackLoginDialogClosed(service)
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun trackDialogClosed(service: TrackService)
|
||||
fun trackLoginDialogClosed(service: TrackService)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
package eu.kanade.tachiyomi.widget.preference
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class TrackLogoutDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
||||
|
||||
private val service = Injekt.get<TrackManager>().getService(args.getInt("key"))!!
|
||||
|
||||
constructor(service: TrackService) : this(Bundle().apply { putInt("key", service.id) })
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(text = activity!!.getString(R.string.logout_from_, service.name))
|
||||
.negativeButton(R.string.cancel)
|
||||
.positiveButton(R.string.logout) { _ ->
|
||||
service.logout()
|
||||
(targetController as? Listener)?.trackLogoutDialogClosed(service)
|
||||
activity!!.toast(R.string.successfully_logged_out)
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun trackLogoutDialogClosed(service: TrackService)
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:background="@color/red_error">
|
||||
tools:background="@color/material_red_500">
|
||||
<item
|
||||
android:bottom="1dp"
|
||||
android:left="-2dp"
|
||||
|
@ -3,7 +3,7 @@
|
||||
<item android:state_activated="true" android:color="@color/md_white_1000">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="2dp" />
|
||||
<solid android:color="@color/red_error" />
|
||||
<solid android:color="@color/material_red_500" />
|
||||
<padding android:left="8dp" android:right="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
@ -15,11 +15,11 @@
|
||||
<padding android:left="8dp" android:right="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:color="@color/red_error">
|
||||
<shape android:color="@color/red_error" android:shape="rectangle">
|
||||
<item android:color="@color/material_red_500">
|
||||
<shape android:color="@color/material_red_500" android:shape="rectangle">
|
||||
<corners android:radius="2dp" />
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<stroke android:width="1dp" android:color="@color/red_error" />
|
||||
<stroke android:width="1dp" android:color="@color/material_red_500" />
|
||||
<padding android:left="8dp" android:right="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
8
app/src/main/res/drawable/ic_close_circle_24dp.xml
Normal file
8
app/src/main/res/drawable/ic_close_circle_24dp.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- drawable/close_circle.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z" />
|
||||
</vector>
|
@ -5,7 +5,7 @@
|
||||
android:height="100dp"
|
||||
android:viewportHeight="10"
|
||||
android:viewportWidth="100"
|
||||
tools:background="@color/red_error">
|
||||
tools:background="@color/material_red_500">
|
||||
|
||||
<path
|
||||
android:fillColor="@color/unread_badge"
|
||||
|
@ -10,7 +10,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:background="@color/red_error">
|
||||
android:background="@color/material_red_500">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close_right"
|
||||
@ -28,7 +28,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:background="@color/red_error">
|
||||
android:background="@color/material_red_500">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close_left"
|
||||
|
@ -88,8 +88,8 @@
|
||||
app:atg_isAppendMode="true"
|
||||
app:atg_inputHintColor="?android:attr/textColorSecondary"
|
||||
app:atg_inputTextColor="?android:attr/textColorPrimary"
|
||||
app:atg_checkedBackgroundColor="@color/red_error"
|
||||
app:atg_checkedBorderColor="@color/red_error"
|
||||
app:atg_checkedBackgroundColor="@color/material_red_500"
|
||||
app:atg_checkedBorderColor="@color/material_red_500"
|
||||
app:atg_borderColor="?attr/colorAccent"
|
||||
app:atg_textColor="?attr/colorAccent" />
|
||||
|
||||
|
@ -1,77 +1,69 @@
|
||||
<?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"
|
||||
android:padding="24dp">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_title"
|
||||
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"/>
|
||||
tools:text="Log in to AniList" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:background="@color/divider"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username_label"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/username_input"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/username"/>
|
||||
android:layout_marginTop="15dp"
|
||||
android:hint="@string/username"
|
||||
app:boxStrokeColor="@color/colorAccent"
|
||||
app:hintTextColor="@color/colorAccent">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/password"/>
|
||||
android:layout_marginTop="12dp"
|
||||
android:hint="@string/password"
|
||||
app:boxStrokeColor="@color/colorAccent"
|
||||
app:endIconMode="password_toggle"
|
||||
app:hintTextColor="@color/colorAccent">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword"/>
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/show_password"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/show_password"/>
|
||||
|
||||
<com.dd.processbutton.iml.ActionProcessButton
|
||||
<br.com.simplepass.loadingbutton.customViews.CircularProgressButton
|
||||
android:id="@+id/login"
|
||||
style="@style/Theme.Widget.Button.Primary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="55dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="20dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:text="@string/login"
|
||||
android:textColor="@android:color/white"
|
||||
app:pb_textComplete="@string/successfully_logged_in"
|
||||
app:pb_textError="@string/could_not_log_in"
|
||||
app:pb_textProgress="@string/loading"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/logout"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:background="@color/md_grey_800"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/logout"
|
||||
android:textColor="?colorAccent"/>
|
||||
android:textSize="16sp"
|
||||
app:finalCornerAngle="50dp"
|
||||
app:initialCornerAngle="2dp"
|
||||
app:spinning_bar_color="@color/md_white_1000"
|
||||
app:spinning_bar_padding="6dp"
|
||||
app:spinning_bar_width="3dp" />
|
||||
|
||||
</LinearLayout>
|
@ -9,7 +9,7 @@
|
||||
android:id="@+id/right_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/red_error"
|
||||
android:background="@color/material_red_500"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
@ -30,7 +30,7 @@
|
||||
android:id="@+id/left_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/red_error">
|
||||
android:background="@color/material_red_500">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/close_left"
|
||||
|
@ -31,9 +31,9 @@
|
||||
<ImageView
|
||||
android:id="@+id/track_logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:contentDescription="@string/tracking"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/tracking"
|
||||
tools:src="@drawable/ic_tracker_mal" />
|
||||
|
||||
<ProgressBar
|
||||
@ -70,11 +70,28 @@
|
||||
android:text="@string/title"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/track_remove"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="dfdffggjdfigjssdfgidfjgidgjdifgjfdgifdjgid" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/track_remove"
|
||||
style="@style/Theme.Widget.CustomImageButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/open_in_webview"
|
||||
android:src="@drawable/ic_close_circle_24dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:tint="@color/text_color_secondary"
|
||||
android:tooltipText="@string/remove_tracking"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/status_container"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@id/track_title"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<View
|
||||
@ -122,9 +139,9 @@
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/card_item_selector"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:maxLines="2"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/score_container"
|
||||
app:layout_constraintStart_toEndOf="@id/track_status"
|
||||
@ -159,10 +176,10 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.25"
|
||||
android:background="@color/strong_divider"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/track_chapters"
|
||||
app:layout_constraintStart_toEndOf="@+id/track_status"
|
||||
app:layout_constraintEnd_toStartOf="@id/track_chapters"/>
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
@ -171,10 +188,10 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.25"
|
||||
android:background="@color/strong_divider"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/score_container"
|
||||
app:layout_constraintStart_toEndOf="@+id/track_chapters"
|
||||
app:layout_constraintEnd_toStartOf="@id/score_container"/>
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
|
@ -1,61 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/track_search"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/title"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"/>
|
||||
android:layout_marginEnd="16dp"
|
||||
android:hint="@string/title"
|
||||
app:boxStrokeColor="@color/colorAccent"
|
||||
app:endIconMode="clear_text"
|
||||
app:hintEnabled="false"
|
||||
app:hintTextColor="@color/colorAccent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/track_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/title"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
android:layout_weight="1"
|
||||
android:elevation="12dp"
|
||||
>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/track_search_list"
|
||||
style="@style/Theme.Widget.CardView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:choiceMode="singleChoice"
|
||||
android:clipToPadding="false"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="10dp"
|
||||
android:footerDividersEnabled="true"
|
||||
android:headerDividersEnabled="true"
|
||||
android:listSelector="@drawable/list_item_selector"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:scrollbars="none"
|
||||
android:visibility="invisible"
|
||||
tools:listitem="@layout/track_search_item"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/divider"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView style="@style/Theme.Widget.CardView.Item"
|
||||
<com.google.android.material.card.MaterialCardView style="@style/Theme.Widget.CardView.Item"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
@ -15,17 +15,17 @@
|
||||
android:id="@+id/track_search_cover"
|
||||
android:layout_width="135dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:contentDescription="@string/cover_of_image"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
tools:src="@mipmap/ic_launcher"/>
|
||||
tools:src="@mipmap/ic_launcher" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/track_search_title"
|
||||
android:layout_width="0dp"
|
||||
@ -147,4 +147,4 @@
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
@ -421,6 +421,8 @@
|
||||
<string name="url_not_set_click_again">Manga URL not set, please click title and select manga again</string>
|
||||
<string name="refresh_tracking">Refresh tracking</string>
|
||||
<string name="add_tracking">Add tracking</string>
|
||||
<string name="remove_tracking">Remove tracking from app</string>
|
||||
<string name="remove_tracking_from_">Also remove from %1$s</string>
|
||||
|
||||
<!-- Migration -->
|
||||
<string name="select_sources">Select sources</string>
|
||||
@ -582,7 +584,7 @@
|
||||
<string name="website">Website</string>
|
||||
<string name="open_source_licenses">Open source licenses</string>
|
||||
|
||||
<!-- Login dialog -->
|
||||
<!-- Login/Logout dialog -->
|
||||
<string name="log_in_to_">Log in to %1$s</string>
|
||||
<string name="username">Username</string>
|
||||
<string name="email">Email address</string>
|
||||
@ -590,7 +592,11 @@
|
||||
<string name="show_password">Show password</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="logout">Logout</string>
|
||||
<string name="logout_from_">Logout from %1$s?</string>
|
||||
|
||||
<string name="successfully_logged_in">Successfully logged in</string>
|
||||
<string name="username_must_not_be_blank">Username or password cannot be blank</string>
|
||||
|
||||
<string name="successfully_logged_out">You are now logged out</string>
|
||||
<string name="could_not_log_in">Could not log in</string>
|
||||
|
||||
|
@ -5,8 +5,7 @@
|
||||
<!--Toolbars-->
|
||||
<!--========-->
|
||||
|
||||
<style name="Theme.ActionBar.Dark.DayNight"
|
||||
parent="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar">
|
||||
<style name="Theme.ActionBar.Dark.DayNight" parent="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar">
|
||||
<item name="popupTheme">@style/ThemeOverlay.MaterialComponents.Light</item>
|
||||
</style>
|
||||
|
||||
@ -202,7 +201,7 @@
|
||||
<!--==============-->
|
||||
<!--Widgets.Button-->
|
||||
<!--==============-->
|
||||
<style name="Theme.Widget.Button" parent="Widget.AppCompat.Button"/>
|
||||
<style name="Theme.Widget.Button" parent="Widget.AppCompat.Button" />
|
||||
|
||||
<style name="Theme.Widget.Button.Colored" parent="Widget.MaterialComponents.Button">
|
||||
<item name="backgroundTint">?attr/colorAccent</item>
|
||||
@ -223,8 +222,7 @@
|
||||
<item name="android:minWidth">48dip</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Widget.Button.RoundedOutline"
|
||||
parent="Widget.MaterialComponents.Button.OutlinedButton.Icon">
|
||||
<style name="Theme.Widget.Button.RoundedOutline" parent="Widget.MaterialComponents.Button.OutlinedButton.Icon">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:letterSpacing">0.0</item>
|
||||
@ -261,6 +259,7 @@
|
||||
<item name="android:tint">?colorAccent</item>
|
||||
</style>
|
||||
|
||||
|
||||
<!--===-->
|
||||
<!--OLD-->
|
||||
<!--===-->
|
||||
|
@ -28,7 +28,7 @@
|
||||
<item name="android:divider">@color/divider</item>
|
||||
<item name="android:listDivider">@drawable/line_divider</item>
|
||||
<item name="actionModeStyle">@style/CustomActionModeStyle</item>
|
||||
|
||||
|
||||
<!-- Themes -->
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.DayNight.ActionBar</item>
|
||||
|
@ -1,7 +1,7 @@
|
||||
object Versions {
|
||||
const val ACRA = "4.9.2"
|
||||
const val CHUCKER = "3.2.0"
|
||||
const val COIL = "0.10.1"
|
||||
const val COIL = "0.11.0"
|
||||
const val COROUTINES = "1.3.5"
|
||||
const val FASTADAPTER = "5.0.0"
|
||||
const val HYPERION = "0.9.27"
|
||||
|
Loading…
Reference in New Issue
Block a user