aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
blob: fadbadf9acc260a0b400c64920c676aac223352b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * Copyright 2018 Allan Wang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.pitchedapps.frost.web

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.View
import android.webkit.ConsoleMessage
import android.webkit.CookieManager
import android.webkit.WebChromeClient
import android.webkit.WebResourceRequest
import android.webkit.WebView
import ca.allanwang.kau.utils.fadeIn
import ca.allanwang.kau.utils.isVisible
import ca.allanwang.kau.utils.launchMain
import com.pitchedapps.frost.db.CookieEntity
import com.pitchedapps.frost.enums.ThemeCategory
import com.pitchedapps.frost.facebook.FB_LOGIN_URL
import com.pitchedapps.frost.facebook.FB_USER_MATCHER
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.USER_AGENT
import com.pitchedapps.frost.facebook.get
import com.pitchedapps.frost.injectors.CssHider
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.injectors.jsInject
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.isFacebookUrl
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.coroutineScope
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

/**
 * Created by Allan Wang on 2017-05-29.
 */
class LoginWebView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : WebView(context, attrs, defStyleAttr), KoinComponent {

    private val fbCookie: FbCookie by inject()
    private val prefs: Prefs by inject()
    private val themeProvider: ThemeProvider by inject()
    private val completable: CompletableDeferred<CookieEntity> = CompletableDeferred()
    private lateinit var progressCallback: (Int) -> Unit

    @SuppressLint("SetJavaScriptEnabled")
    private fun setupWebview() {
        settings.javaScriptEnabled = true
        settings.userAgentString = USER_AGENT
        setLayerType(View.LAYER_TYPE_HARDWARE, null)
        webViewClient = LoginClient()
        webChromeClient = LoginChromeClient()
    }

    suspend fun loadLogin(progressCallback: (Int) -> Unit): CompletableDeferred<CookieEntity> =
        coroutineScope {
            this@LoginWebView.progressCallback = progressCallback
            L.d { "Begin loading login" }
            launchMain {
                fbCookie.reset()
                setupWebview()
                loadUrl(FB_LOGIN_URL)
            }
            completable
        }

    private inner class LoginClient : BaseWebViewClient() {

        override fun onPageFinished(view: WebView, url: String?) {
            super.onPageFinished(view, url)
            val cookie = checkForLogin(url)
            if (cookie != null)
                completable.complete(cookie)
            if (!view.isVisible) view.fadeIn()
        }

        fun checkForLogin(url: String?): CookieEntity? {
            if (!url.isFacebookUrl) return null
            val cookie = CookieManager.getInstance().getCookie(url) ?: return null
            L.d { "Checking cookie for login" }
            val id = FB_USER_MATCHER.find(cookie)[1]?.toLong() ?: return null
            return CookieEntity(id, null, cookie)
        }

        override fun onPageCommitVisible(view: WebView, url: String?) {
            super.onPageCommitVisible(view, url)
            L.d { "Login page commit visible" }
            view.setBackgroundColor(Color.TRANSPARENT)
            if (url.isFacebookUrl)
                view.jsInject(
                    CssHider.CORE,
                    themeProvider.injector(ThemeCategory.FACEBOOK),
                    prefs = prefs
                )
        }

        override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
            // For now, we will ignore all attempts to launch external apps during login
            if (request.url == null || request.url.scheme == "intent" || request.url.scheme == "android-app")
                return true
            return super.shouldOverrideUrlLoading(view, request)
        }
    }

    private inner class LoginChromeClient : WebChromeClient() {
        override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
            L.v { "Login Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}" }
            return true
        }

        override fun onProgressChanged(view: WebView, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
            progressCallback(newProgress)
        }
    }
}