diff options
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/activities')
9 files changed, 223 insertions, 53 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt index 1e17f06a..ffcbadab 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt @@ -123,7 +123,12 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, // Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) // .setAction("Action", null).show() // } - setFrostColors(toolbar, themeWindow = false, headers = arrayOf(appBar), backgrounds = arrayOf(viewPager)) + setFrostColors { + toolbar(toolbar) + themeWindow = false + header(appBar) + background(viewPager) + } tabs.setBackgroundColor(Prefs.mainActivityLayout.backgroundColor()) onCreateBilling() } @@ -192,8 +197,8 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, } } } - -3L -> launchNewTask(LoginActivity::class.java, clearStack = false) - -4L -> launchNewTask(SelectorActivity::class.java, cookies(), false) + -3L -> launchNewTask<LoginActivity>(clearStack = false) + -4L -> launchNewTask<SelectorActivity>( cookies(), false) else -> { FbCookie.switchUser(profile.identifier, this@BaseMainActivity::refreshAll) tabsForEachView { _, view -> view.badgeText = null } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt new file mode 100644 index 00000000..b6becf90 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt @@ -0,0 +1,75 @@ +package com.pitchedapps.frost.activities + +import android.app.Activity +import android.content.Intent +import android.content.res.ColorStateList +import android.os.Bundle +import android.support.design.widget.FloatingActionButton +import android.support.v4.widget.SwipeRefreshLayout +import android.support.v7.widget.Toolbar +import ca.allanwang.kau.internal.KauBaseActivity +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.setIcon +import ca.allanwang.kau.utils.visible +import com.mikepenz.google_material_typeface_library.GoogleMaterial +import com.pitchedapps.frost.R +import com.pitchedapps.frost.facebook.FbItem +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.setFrostColors +import com.pitchedapps.frost.web.DebugWebView + +/** + * Created by Allan Wang on 05/01/18. + */ +class DebugActivity : KauBaseActivity(), SwipeRefreshLayout.OnRefreshListener { + + private val toolbar: Toolbar by bindView(R.id.toolbar) + private val web: DebugWebView by bindView(R.id.debug_webview) + private val swipeRefresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh) + private val fab: FloatingActionButton by bindView(R.id.fab) + + companion object { + const val RESULT_URL = "extra_result_url" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_debug) + setSupportActionBar(toolbar) + setTitle(R.string.debug_frost) + setFrostColors { + toolbar(toolbar) + } + web.loadUrl(FbItem.FEED.url) + web.onPageFinished = { swipeRefresh.isRefreshing = false } + fab.visible().setIcon(GoogleMaterial.Icon.gmd_bug_report, Prefs.iconColor) + fab.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor) + fab.setOnClickListener { + val intent = Intent() + intent.putExtra(RESULT_URL, web.url) + setResult(Activity.RESULT_OK, intent) + finish() + } + } + + override fun onRefresh() { + web.reload() + } + + override fun onResume() { + super.onResume() + web.resumeTimers() + } + + override fun onPause() { + web.pauseTimers() + super.onPause() + } + + override fun onBackPressed() { + if (web.canGoBack()) + web.goBack() + else + super.onBackPressed() + } +}
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt index d63fa25e..99fa6eee 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -1,5 +1,6 @@ package com.pitchedapps.frost.activities +import android.content.Context import android.content.Intent import android.content.res.ColorStateList import android.graphics.Bitmap @@ -7,18 +8,20 @@ import android.graphics.Color import android.graphics.drawable.Drawable import android.net.Uri import android.os.Bundle +import android.os.Environment import android.support.design.widget.FloatingActionButton -import android.support.v4.content.FileProvider import android.view.View import android.view.ViewGroup import android.widget.ProgressBar import android.widget.TextView import ca.allanwang.kau.internal.KauBaseActivity +import ca.allanwang.kau.logging.KauLoggerExtension import ca.allanwang.kau.mediapicker.scanMedia import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE import ca.allanwang.kau.permissions.kauRequestPermissions import ca.allanwang.kau.utils.* import com.bumptech.glide.Glide +import com.bumptech.glide.RequestManager import com.bumptech.glide.request.target.BaseTarget import com.bumptech.glide.request.target.SizeReadyCallback import com.bumptech.glide.request.target.Target @@ -27,14 +30,17 @@ import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.typeface.IIcon -import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.R +import com.pitchedapps.frost.facebook.requests.call import com.pitchedapps.frost.utils.* import com.sothree.slidinguppanel.SlidingUpPanelLayout +import okhttp3.Request import org.jetbrains.anko.activityUiThreadWithContext import org.jetbrains.anko.doAsync import java.io.File import java.io.IOException +import java.text.SimpleDateFormat +import java.util.* /** * Created by Allan Wang on 2017-07-15. @@ -49,17 +55,19 @@ class ImageActivity : KauBaseActivity() { val fab: FloatingActionButton by bindView(R.id.image_fab) var errorRef: Throwable? = null + private val tempDir: File by lazy { File(cacheDir, IMAGE_FOLDER) } + /** * Reference to the temporary file path * Should be nonnull if the image is successfully loaded * As this is temporary, the image is deleted upon exit */ - private var tempFilePath: String? = null + internal var tempFile: File? = null /** * Reference to path for downloaded image * Nonnull once the image is downloaded by the user */ - internal var downloadPath: String? = null + internal var savedFile: File? = null /** * Indicator for fab's click result */ @@ -70,15 +78,28 @@ class ImageActivity : KauBaseActivity() { value.update(fab) } + companion object { + /** + * Cache folder to store images + * Linked to the uri provider + */ + private const val IMAGE_FOLDER = "images" + private const val TIME_FORMAT = "yyyyMMdd_HHmmss" + private const val IMG_TAG = "Frost" + private const val IMG_EXTENSION = ".png" + private val L = KauLoggerExtension("Image", com.pitchedapps.frost.utils.L) + } + val imageUrl: String by lazy { intent.getStringExtra(ARG_IMAGE_URL).trim('"') } val text: String? by lazy { intent.getStringExtra(ARG_TEXT) } + private val glide: RequestManager by lazy { Glide.with(this) } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) intent?.extras ?: return finish() L.i { "Displaying image" } - L._i { imageUrl } val layout = if (!text.isNullOrBlank()) R.layout.activity_image else R.layout.activity_image_textless setContentView(layout) container.setBackgroundColor(Prefs.bgColor.withMinAlpha(222)) @@ -101,8 +122,10 @@ class ImageActivity : KauBaseActivity() { imageCallback(null, false) } }) - Glide.with(this).asBitmap().load(imageUrl).into(PhotoTarget(this::imageCallback)) - setFrostColors(themeWindow = false) + glide.asBitmap().load(imageUrl).into(PhotoTarget(this::imageCallback)) + setFrostColors { + themeWindow = false + } } /** @@ -119,7 +142,7 @@ class ImageActivity : KauBaseActivity() { } else { photo.setImage(ImageSource.uri(it)) fabAction = FabStates.DOWNLOAD - photo.animate().alpha(1f).scaleXY(1f).withEndAction { fab.show() }.start() + photo.animate().alpha(1f).scaleXY(1f).withEndAction(fab::show).start() } }) } else { @@ -135,52 +158,105 @@ class ImageActivity : KauBaseActivity() { override fun removeCallback(cb: SizeReadyCallback?) {} - override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) = callback(resource, true) + override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) = + callback(resource, true) - override fun onLoadFailed(errorDrawable: Drawable?) = callback(null, false) + override fun onLoadFailed(errorDrawable: Drawable?) = + callback(null, false) - override fun getSize(cb: SizeReadyCallback) = cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) + override fun getSize(cb: SizeReadyCallback) = + cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) } private fun saveTempImage(resource: Bitmap, callback: (uri: Uri?) -> Unit) { var photoFile: File? = null try { - photoFile = createPrivateMediaFile(".png") + photoFile = createPrivateMediaFile() } catch (e: IOException) { errorRef = e + logImage(e) } finally { if (photoFile == null) { callback(null) } else { - tempFilePath = photoFile.absolutePath - L.d { "Temp image path $tempFilePath" } + tempFile = photoFile + L.d { "Temp image path ${tempFile?.absolutePath}" } // File created; proceed with request - val photoURI = FileProvider.getUriForFile(this, - BuildConfig.APPLICATION_ID + ".provider", - photoFile) + val photoURI = frostUriFromFile(photoFile) photoFile.outputStream().use { resource.compress(Bitmap.CompressFormat.PNG, 100, it) } callback(photoURI) } } } - internal fun downloadImage() { + private fun logImage(e: Exception?) { + if (!Prefs.analytics) return + val error = e ?: IOException("$imageUrl failed to load") + L.e(error) { "$imageUrl failed to load" } + } + + @Throws(IOException::class) + private fun createPrivateMediaFile(): File { + val timeStamp = SimpleDateFormat(TIME_FORMAT, Locale.getDefault()).format(Date()) + val imageFileName = "${IMG_TAG}_${timeStamp}_" + if (!tempDir.exists()) + tempDir.mkdirs() + return File.createTempFile(imageFileName, IMG_EXTENSION, tempDir) + } + + @Throws(IOException::class) + private fun createPublicMediaFile(): File { + val timeStamp = SimpleDateFormat(TIME_FORMAT, Locale.getDefault()).format(Date()) + val imageFileName = "${IMG_TAG}_${timeStamp}_" + val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + val frostDir = File(storageDir, IMG_TAG) + if (!frostDir.exists()) frostDir.mkdirs() + return File.createTempFile(imageFileName, IMG_EXTENSION, frostDir) + } + + @Throws(IOException::class) + private fun downloadImageTo(file: File) { + val body = Request.Builder() + .url(imageUrl) + .get() + .call() + .execute() + .body() ?: throw IOException("Failed to retrieve image body") + body.byteStream().use { input -> + file.outputStream().use { output -> + input.copyTo(output) + } + } + } + + internal fun saveImage() { kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ -> L.d { "Download image callback granted: $granted" } if (granted) { doAsync { - val destination = createMediaFile(".png") - downloadPath = destination.absolutePath + val destination = createPublicMediaFile() var success = true try { - File(tempFilePath).copyTo(destination, true) - scanMedia(destination) + val temp = tempFile + if (temp != null) + temp.copyTo(destination, true) + else + downloadImageTo(destination) } catch (e: Exception) { errorRef = e success = false } finally { L.d { "Download image async finished: $success" } + if (success) { + scanMedia(destination) + savedFile = destination + } else { + try { + destination.delete() + } catch (ignore: Exception) { + } + } activityUiThreadWithContext { val text = if (success) R.string.image_download_success else R.string.image_download_fail frostSnackbar(text) @@ -192,15 +268,9 @@ class ImageActivity : KauBaseActivity() { } } - internal fun deleteTempFile() { - if (tempFilePath != null) { - File(tempFilePath!!).delete() - tempFilePath = null - } - } - override fun onDestroy() { - deleteTempFile() + tempFile = null + tempDir.deleteRecursively() L.d { "Closing $localClassName" } super.onDestroy() } @@ -229,14 +299,12 @@ internal enum class FabStates(val iicon: IIcon, val iconColor: Int = Prefs.iconC override fun onClick(activity: ImageActivity) {} }, DOWNLOAD(GoogleMaterial.Icon.gmd_file_download) { - override fun onClick(activity: ImageActivity) = activity.downloadImage() + override fun onClick(activity: ImageActivity) = activity.saveImage() }, SHARE(GoogleMaterial.Icon.gmd_share) { override fun onClick(activity: ImageActivity) { try { - val photoURI = FileProvider.getUriForFile(activity, - BuildConfig.APPLICATION_ID + ".provider", - File(activity.downloadPath)) + val photoURI = activity.frostUriFromFile(activity.savedFile!!) val intent = Intent(Intent.ACTION_SEND).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK putExtra(Intent.EXTRA_STREAM, photoURI) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt index 2321a936..9babd431 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt @@ -134,7 +134,7 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On } override fun finish() { - launchNewTask(MainActivity::class.java, cookies()) + launchNewTask<MainActivity>(cookies()) super.finish() } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt index e9657934..2434c8c2 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -62,7 +62,9 @@ class LoginActivity : BaseActivity() { setContentView(R.layout.activity_login) setSupportActionBar(toolbar) setTitle(R.string.kau_login) - setFrostColors(toolbar) + setFrostColors{ + toolbar(toolbar) + } web.loadLogin({ refresh = it != 100 }) { cookie -> L.d { "Login found" } FbCookie.save(cookie.id) @@ -97,10 +99,13 @@ class LoginActivity : BaseActivity() { * The user may have logged into an account that is already in the database * We will let the db handle duplicates and load it now after the new account has been saved */ - loadFbCookiesAsync { cookies -> + loadFbCookiesAsync { + val cookies = ArrayList(it) Handler().postDelayed({ - launchNewTask(if (Showcase.intro) IntroActivity::class.java else MainActivity::class.java, - ArrayList(cookies), clearStack = true) + if (Showcase.intro) + launchNewTask<IntroActivity>(cookies, true) + else + launchNewTask<MainActivity>(cookies, true) }, 1000) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt index ff87f448..a9658eb1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt @@ -38,10 +38,13 @@ class SelectorActivity : BaseActivity() { override fun onBind(viewHolder: RecyclerView.ViewHolder): View? = (viewHolder as? AccountItem.ViewHolder)?.v override fun onClick(v: View, position: Int, fastAdapter: FastAdapter<AccountItem>, item: AccountItem) { - if (item.cookie == null) this@SelectorActivity.launchNewTask(LoginActivity::class.java) - else FbCookie.switchUser(item.cookie, { launchNewTask(MainActivity::class.java, cookies()) }) + if (item.cookie == null) this@SelectorActivity.launchNewTask<LoginActivity>() + else FbCookie.switchUser(item.cookie, { launchNewTask<MainActivity>(cookies()) }) } }) - setFrostColors(texts = arrayOf(text), backgrounds = arrayOf(container)) + setFrostColors { + text(text) + background(container) + } } }
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt index 58e73530..93d303ab 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt @@ -38,14 +38,23 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() { const val REQUEST_NOTIFICATION_RINGTONE = REQUEST_RINGTONE or 1 const val REQUEST_MESSAGE_RINGTONE = REQUEST_RINGTONE or 2 const val ACTIVITY_REQUEST_TABS = 29 + const val ACTIVITY_REQUEST_DEBUG = 53 } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (fetchRingtone(requestCode, resultCode, data)) return - if (requestCode == ACTIVITY_REQUEST_TABS) { - if (resultCode == Activity.RESULT_OK) - shouldRestartMain() - return + when (requestCode) { + ACTIVITY_REQUEST_TABS -> { + if (resultCode == Activity.RESULT_OK) + shouldRestartMain() + return + } + ACTIVITY_REQUEST_DEBUG -> { + val url = data?.extras?.getString(DebugActivity.RESULT_URL) + if (url?.isNotBlank() == true) + sendDebug(url) + return + } } if (!onActivityResultBilling(requestCode, resultCode, data)) super.onActivityResult(requestCode, resultCode, data) @@ -127,7 +136,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() { descRes = R.string.about_frost_desc iicon = GoogleMaterial.Icon.gmd_info onClick = { - startActivityForResult(AboutActivity::class.java, 9, bundleBuilder = { + startActivityForResult<AboutActivity>(9, bundleBuilder = { withSceneTransitionAnimation(this@SettingsActivity) }) } @@ -141,7 +150,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() { plainText(R.string.replay_intro) { iicon = GoogleMaterial.Icon.gmd_replay - onClick = { launchIntroActivity(cookies()) } + onClick = { launchNewTask<IntroActivity>(cookies(), true) } } subItems(R.string.debug_frost, getDebugPrefs()) { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt index ca7a231d..554eaa00 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt @@ -79,7 +79,9 @@ class TabCustomizerActivity : BaseActivity() { fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, Prefs.iconColor) fabCancel.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor) fabCancel.setOnClickListener { finish() } - setFrostColors(themeWindow = true) + setFrostColors { + themeWindow = true + } } private fun View.wobble() = startAnimation(wobble(context)) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt index 853ade72..1bd3ede2 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt @@ -147,7 +147,10 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc toolbar.navigationIcon = GoogleMaterial.Icon.gmd_close.toDrawable(this, 16, Prefs.iconColor) toolbar.setNavigationOnClickListener { finishSlideOut() } - setFrostColors(toolbar, themeWindow = false) + setFrostColors { + toolbar(toolbar) + themeWindow = false + } coordinator.setBackgroundColor(Prefs.bgColor.withAlpha(255)) content.bind(this) |