1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-08 20:12:39 +01:00

setup login activity

This commit is contained in:
Allan Wang 2017-06-03 13:22:06 -07:00
parent 5796566137
commit 35185958b0
20 changed files with 203 additions and 123 deletions

View File

@ -5,12 +5,6 @@
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="MarkdownProjectSettings">
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.25" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="LINE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="true" showSelectionInPreview="true">
<PanelProvider>
@ -71,30 +68,6 @@
<textMaps />
</LinkMapSettings>
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
@ -121,10 +94,26 @@
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="true" assert-keyword="true" jdk-15="true">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.8</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

View File

@ -3,7 +3,6 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Frost-for-Facebook.iml" filepath="$PROJECT_DIR$/Frost-for-Facebook.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>

View File

@ -1,3 +0,0 @@
<component name="DependencyValidationManager">
<scope name="CSS" pattern="file[Frost-for-Facebook]:scss/*" />
</component>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,17 @@
@mixin placeholder {
::-webkit-input-placeholder {
@content
}
:-moz-placeholder {
@content
}
::-moz-placeholder {
@content
}
:-ms-input-placeholder {
@content
}
}

View File

@ -1,3 +1,5 @@
[data-sigil="m_login_upsell"] { display: none !important; }
body, #root, #header, .aclb, ._55wo, ._1upc, input { background: #000 !important; }
button::before, ._56be::before, .btnS, .touch::before { background: #111 !important; }
@ -6,7 +8,15 @@ button::before, ._56be::before, .btnS, .touch::before { background: #111 !import
.touch .btnS { box-shadow: none !important; }
input, ._43mh, .touch .btn, a, .fcg, button, ._52j9, ::-webkit-input-placeholder, ::-moz-placeholder, ::-ms-input-placeholder { color: #fff !important; }
input, ._43mh, .touch .btn, a, .fcg, button, ._52j9 { color: #fff !important; }
::-webkit-input-placeholder { color: #fff !important; }
:-moz-placeholder { color: #fff !important; }
::-moz-placeholder { color: #fff !important; }
:-ms-input-placeholder { color: #fff !important; }
._43mh::before, ._43mh::after { background: #fff !important; }

View File

@ -1,6 +1,12 @@
@import "colors";
@import "base";
body, #root,#header,.aclb,._55wo,._1upc,input {
//Get Android banner
[data-sigil="m_login_upsell"] {
display: none !important;
}
body, #root, #header, .aclb, ._55wo, ._1upc, input {
background: $background !important;
}
@ -17,13 +23,18 @@ button::before, ._56be::before, .btnS, .touch::before {
box-shadow: none !important;
}
input,._43mh, .touch .btn,a, .fcg, button, ._52j9, ::-webkit-input-placeholder,::-moz-placeholder ,::-ms-input-placeholder {
color: $text !important
input, ._43mh, .touch .btn, a, .fcg, button, ._52j9 {
color: $text !important;
}
@include placeholder {
color: $text !important;
}
// divider lines
._43mh::before, ._43mh::after {
background: $text !important
background: $text !important;
}
._1rrd {

View File

@ -18,12 +18,24 @@ import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.pitchedapps.frost.dbflow.CookieModel
import com.pitchedapps.frost.dbflow.saveFbCookie
import com.pitchedapps.frost.facebook.FACEBOOK_COM
import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.bindView
import com.pitchedapps.frost.views.fadeIn
import com.pitchedapps.frost.views.fadeOut
import com.pitchedapps.frost.views.setTextWithFade
import com.pitchedapps.frost.web.LoginWebView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.BiFunction
import io.reactivex.internal.operators.single.SingleToObservable
import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.SingleSubject
import org.jsoup.Jsoup
import kotlin.concurrent.thread
/**
@ -33,21 +45,33 @@ class LoginActivity : AppCompatActivity() {
val toolbar: Toolbar by bindView(R.id.toolbar)
val web: LoginWebView by bindView(R.id.login_webview)
val refresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh)
val swipeRefresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh)
val textview: AppCompatTextView by bindView(R.id.textview)
val profile: ImageView by bindView(R.id.profile)
val loginObservable = SingleSubject.create<CookieModel>()
val progressObservable = BehaviorSubject.create<Int>()
val loginObservable = SingleSubject.create<CookieModel>()!!
val progressObservable = BehaviorSubject.create<Int>()!!
val profileObservable = SingleSubject.create<Boolean>()!!
val usernameObservable = SingleSubject.create<String>()!!
companion object {
fun newInstance(context: Context) {
val intent = Intent(context, LoginActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
val bundle = ActivityOptionsCompat.makeCustomAnimation(context, R.anim.slide_in_right, R.anim.slide_out_right).toBundle()
ContextCompat.startActivity(context, intent, bundle)
}
}
// Helper to set and enable swipeRefresh
var refresh: Boolean
get() = swipeRefresh.isRefreshing
set(value) {
if (value) swipeRefresh.isEnabled = true
swipeRefresh.isRefreshing = value
if (!value) swipeRefresh.isEnabled = false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
@ -56,26 +80,62 @@ class LoginActivity : AppCompatActivity() {
web.loginObservable = loginObservable
web.progressObservable = progressObservable
loginObservable.observeOn(AndroidSchedulers.mainThread()).subscribe {
cookieModel ->
Glide.with(this@LoginActivity).load(PROFILE_PICTURE_URL(cookieModel.id)).listener(object : RequestListener<Drawable> {
cookie ->
web.fadeOut(onFinish = {
profile.fadeIn()
textview.fadeIn()
loadInfo(cookie)
})
}
progressObservable.observeOn(AndroidSchedulers.mainThread()).subscribe { refresh = it != 100 }
web.loadLogin()
}
fun loadInfo(cookie: CookieModel) {
refresh = true
Observable.zip(SingleToObservable(profileObservable), SingleToObservable(usernameObservable),
BiFunction<Boolean, String, Pair<Boolean, String>> { foundImage, name -> Pair(foundImage, name) })
.observeOn(AndroidSchedulers.mainThread()).subscribe {
(foundImage, name) ->
refresh = false
L.d("Zip done")
if (!foundImage) L.e("Could not get profile photo; Invalid id?\n\t$cookie")
textview.setTextWithFade(String.format(getString(R.string.welcome), name), duration = 500)
}
loadProfile(cookie.id)
loadUsername(cookie)
}
fun loadProfile(id: Long) {
Glide.with(this@LoginActivity).load(PROFILE_PICTURE_URL(id)).listener(object : RequestListener<Drawable> {
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
profileObservable.onSuccess(true)
return false
}
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
profileObservable.onSuccess(false)
return false
}
}).into(profile)
}
progressObservable.observeOn(AndroidSchedulers.mainThread()).subscribe {
val loading = it != 100
if (loading) refresh.isEnabled = true
refresh.isRefreshing = loading
if (!loading) refresh.isEnabled = false
}
web.loadLogin()
}
fun loadUsername(cookie: CookieModel) {
thread {
var name = ""
try {
name = Jsoup.connect(FbTab.PROFILE.url)
.cookie(FACEBOOK_COM, cookie.cookie)
.get().title()
L.d("User name found: $name")
} catch (e: Exception) {
L.e("User name fetching failed: ${e.message}")
} finally {
cookie.name = name
saveFbCookie(cookie)
usernameObservable.onSuccess(name)
}
}
}
}

View File

@ -145,7 +145,7 @@ class MainActivity : AppCompatActivity() {
// finish()
}
R.id.action_changelog -> Changelog.show(this)
R.id.action_call -> WebOverlayActivity.newInstance(this, "https://www.google.ca")
R.id.action_call -> LoginActivity.newInstance(this)
R.id.action_db -> adapter.pages.saveAsync(this)
R.id.action_restart -> {
finish();

View File

@ -42,12 +42,12 @@ fun loadFbCookiesAsync(callback: (cookies: List<CookieModel>) -> Unit) {
fun saveFbCookie(cookie: CookieModel) {
cookie.async save {
L.d("Fb cookie saved")
L.d("Fb cookie $cookie saved")
}
}
fun removeCookie(id: Long) {
loadFbCookie(id)?.async?.delete({
L.d("Fb cookie deleted")
L.d("Fb cookie $id deleted")
})
}

View File

@ -32,10 +32,10 @@ class FbAccountEvent(val data: CookieModel, val sender: Int, val flag: Int) {
}
fun execute(webView: FrostWebViewCore) {
if (sender != -1 && sender == webView.position) return
when (flag) {
FLAG_LOGOUT, FLAG_RESET, FLAG_NEW, FLAG_SWITCH -> webView.loadBaseUrl()
}
// if (sender != -1 && sender == webView.position) return
// when (flag) {
// FLAG_LOGOUT, FLAG_RESET, FLAG_NEW, FLAG_SWITCH -> webView.loadBaseUrl()
// }
}
/**
@ -51,8 +51,8 @@ class FbAccountEvent(val data: CookieModel, val sender: Int, val flag: Int) {
.withIcon(PROFILE_PICTURE_URL(data.id))
accountHeader.addProfile(profile, 0)
accountHeader.setActiveProfile(profile, true)
if (data.name == null)
UsernameFetcher.fetch(data, sender)
// if (data.name == null)
// UsernameFetcher.fetch(data, sender)
}
FLAG_USER_NAME -> {
if (accountHeader.activeProfile.name == null)

View File

@ -32,57 +32,37 @@ object FbCookie {
}
}
private val userMatcher: Regex by lazy { Regex("c_user=([0-9]*);") }
fun hasLoggedIn(url: String, cookie: String?):Boolean {
if (cookie == null || !url.contains("facebook") || !cookie.contains(userMatcher)) return false
L.d("Checking cookie for $url\n\t$cookie")
val id = userMatcher.find(cookie)?.groups?.get(1)?.value
if (id != null) {
try {
save(id.toLong(), -1)
return true
} catch (e: NumberFormatException) {
//todo send report that id has changed
}
}
return false
}
fun save(id: Long, sender: Int) {
fun save(id: Long) {
L.d("New cookie found for $id")
Prefs.userId = id
CookieManager.getInstance().flush()
val cookie = CookieModel(Prefs.userId, "", webCookie)
EventBus.getDefault().post(FbAccountEvent(cookie, sender, FbAccountEvent.FLAG_NEW))
saveFbCookie(cookie)
}
//TODO reset when new account is added; reset and clear when account is logged out
fun reset(loggedOut: Boolean = false, sender: Int) {
fun reset() {
Prefs.userId = Prefs.userIdDefault
with(CookieManager.getInstance()) {
removeAllCookies(null)
flush()
}
EventBus.getDefault().post(FbAccountEvent(CookieModel(), sender, if (loggedOut) FbAccountEvent.FLAG_LOGOUT else FbAccountEvent.FLAG_RESET))
}
fun switchUser(id: Long, sender: Int) = switchUser(loadFbCookie(id), sender)
fun switchUser(id: Long) = switchUser(loadFbCookie(id))
fun switchUser(name: String, sender: Int) = switchUser(loadFbCookie(name), sender)
fun switchUser(name: String) = switchUser(loadFbCookie(name))
fun switchUser(cookie: CookieModel?, sender: Int) {
fun switchUser(cookie: CookieModel?) {
if (cookie == null) return
Prefs.userId = cookie.id
dbCookie = cookie.cookie
webCookie = dbCookie
EventBus.getDefault().post(FbAccountEvent(cookie, sender, FbAccountEvent.FLAG_SWITCH))
//TODO add webview refresh event
}
fun logout(sender: Int) {
L.d("Logging out user ${Prefs.userId}")
removeCookie(Prefs.userId)
reset(true, sender)
fun logout(id:Long) {
L.d("Logging out user $id")
removeCookie(id)
reset()
}
}

View File

@ -2,9 +2,8 @@ package com.pitchedapps.frost.facebook
import com.pitchedapps.frost.dbflow.CookieModel
import com.pitchedapps.frost.dbflow.saveFbCookie
import com.pitchedapps.frost.events.FbAccountEvent
import com.pitchedapps.frost.utils.L
import org.greenrobot.eventbus.EventBus
import io.reactivex.subjects.SingleSubject
import org.jsoup.Jsoup
import kotlin.concurrent.thread
@ -13,22 +12,20 @@ import kotlin.concurrent.thread
*/
object UsernameFetcher {
fun fetch(data: CookieModel, sender: Int) {
fun fetch(data: CookieModel, callback: SingleSubject<String>) {
thread {
var name = ""
try {
val title = Jsoup.connect(FbTab.PROFILE.url)
name = Jsoup.connect(FbTab.PROFILE.url)
.cookie(FACEBOOK_COM, data.cookie)
.get().title()
L.d("User name found: $title")
data.name = title
L.d("User name found: $name")
} catch (e: Exception) {
L.e("User name fetching failed: ${e.message}")
data.name = ""
} finally {
if (data.name != null) {
data.name = name
saveFbCookie(data)
EventBus.getDefault().post(FbAccountEvent(data, sender, FbAccountEvent.FLAG_USER_NAME))
}
callback.onSuccess(name)
}
}
}

View File

@ -2,11 +2,13 @@ package com.pitchedapps.frost.views
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.support.annotation.StringRes
import android.view.View
import android.view.ViewAnimationUtils
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.view.animation.DecelerateInterpolator
import android.widget.TextView
/**
@ -105,3 +107,13 @@ fun View.fadeOut(offset: Long = 0L, duration: Long = 200L, onStart: (() -> Unit)
})
startAnimation(anim)
}
fun TextView.setTextWithFade(text: String, duration: Long = 200, onFinish: (() -> Unit)? = null) {
fadeOut(duration = duration, onFinish = {
setText(text)
fadeIn(duration = duration, onFinish = onFinish)
})
}
fun TextView.setTextWithFade(@StringRes textId: Int, duration: Long = 200, onFinish: (() -> Unit)? = null) = setTextWithFade(context.getString(textId), duration, onFinish)

View File

@ -9,6 +9,7 @@ import android.support.v4.content.ContextCompat
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
/**

View File

@ -3,10 +3,12 @@ package com.pitchedapps.frost.web
import android.graphics.Bitmap
import android.view.KeyEvent
import android.webkit.*
import com.pitchedapps.frost.LoginActivity
import com.pitchedapps.frost.facebook.FACEBOOK_COM
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.injectors.CssAssets
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.views.circularReveal
import com.pitchedapps.frost.views.fadeOut
@ -28,14 +30,19 @@ class FrostWebViewClient(val position: () -> Int) : WebViewClient() {
super.onPageStarted(view, url, favicon)
L.i("FWV Loading $url")
if (!url.contains(FACEBOOK_COM)) return
if (url.contains("logout.php")) FbCookie.logout(position.invoke())
if (url.contains("logout.php")) {
FbCookie.logout(Prefs.userId)
LoginActivity.newInstance(view.context)
} else if (url.contains("login.php")) {
FbCookie.reset()
LoginActivity.newInstance(view.context)
}
view.fadeOut(duration = 200L)
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
if (!url.contains(FACEBOOK_COM)) return
FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url), position.invoke())
CssAssets.HEADER.inject(view, {
view.circularReveal(offset = 150L)
})

View File

@ -39,6 +39,7 @@ class LoginWebView @JvmOverloads constructor(
lateinit var progressObservable: Subject<Int>
init {
FbCookie.reset()
cookieObservable.filter { (_, cookie) -> cookie?.contains(userMatcher) ?: false }
.subscribe {
(url, cookie) ->
@ -46,9 +47,10 @@ class LoginWebView @JvmOverloads constructor(
val id = userMatcher.find(cookie!!)?.groups?.get(1)?.value
if (id != null) {
try {
FbCookie.save(id.toLong(), -1)
FbCookie.save(id.toLong())
//TODO proceed to next view
cookieObservable.onComplete()
loginObservable.onSuccess(CookieModel(id.toLong(), "", cookie))
} catch (e: NumberFormatException) {
//todo send report that id has changed
}

View File

@ -15,15 +15,17 @@
android:layout_centerInParent="true"
android:layout_marginBottom="8dp"
android:contentDescription="Profile Picture"
android:scaleType="centerInside"/>
android:scaleType="centerInside"
android:visibility="invisible" />
<android.support.v7.widget.AppCompatTextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/profile"
android:visibility="gone" />
android:layout_centerHorizontal="true"
android:text="@string/loading_account"
android:visibility="invisible" />
<com.pitchedapps.frost.web.LoginWebView
android:id="@+id/login_webview"

View File

@ -20,4 +20,6 @@
<string name="birthdays">Birthdays</string>
<string name="chat">Chat</string>
<string name="photos">Photos</string>
<string name="loading_account">Getting everything ready…</string>
<string name="welcome">Welcome %s</string>
</resources>