diff options
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/utils')
6 files changed, 303 insertions, 0 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Changelog.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Changelog.kt new file mode 100644 index 00000000..14a095a1 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Changelog.kt @@ -0,0 +1,98 @@ +package com.pitchedapps.frost.utils + +import android.content.Context +import android.content.res.XmlResourceParser +import android.os.Handler +import android.support.annotation.LayoutRes +import android.support.annotation.NonNull +import android.support.annotation.XmlRes +import android.support.v4.app.FragmentActivity +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import com.afollestad.materialdialogs.MaterialDialog +import com.pitchedapps.frost.R +import org.xmlpull.v1.XmlPullParser +import java.util.* + + +/** + * Created by Allan Wang on 2017-05-28. + */ +class Changelog { + companion object { + fun show(@NonNull activity: FragmentActivity, @XmlRes xmlRes: Int = R.xml.changelog) { + val mHandler = Handler() + Thread(Runnable { + val items = parse(activity, xmlRes) + mHandler.post(object : TimerTask() { + override fun run() { + MaterialDialog.Builder(activity) + .title(R.string.changelog) + .positiveText(R.string.great) + .adapter(ChangelogAdapter(items), null) + .show() + } + }) + }).start() + } + } +} + +private class ChangelogAdapter(val items: List<Pair<String, ChangelogType>>) : RecyclerView.Adapter<ChangelogAdapter.ChangelogVH>() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ChangelogVH(LayoutInflater.from(parent.context) + .inflate(getLayout(viewType), parent, false)) + + private fun getLayout(position: Int) = items[position].second.layout + + override fun onBindViewHolder(holder: ChangelogVH, position: Int) { + holder.text.text = items[position].first + } + + override fun getItemId(position: Int) = position.toLong() + + override fun getItemViewType(position: Int) = position + + override fun getItemCount() = items.size + + internal class ChangelogVH(itemView: View) : RecyclerView.ViewHolder(itemView) { + val text: TextView = itemView.findViewById(R.id.changelog_text) as TextView + } +} + +private fun parse(context: Context, @XmlRes xmlRes: Int): List<Pair<String, ChangelogType>> { + val items = mutableListOf<Pair<String, ChangelogType>>() + context.resources.getXml(xmlRes).use { + parser -> + var eventType = parser.eventType + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) + ChangelogType.values.any { it.add(parser, items) } + eventType = parser.next() + } + } + return items +} + +private enum class ChangelogType(val tag: String, val attr: String, @LayoutRes val layout: Int) { + TITLE("title", "version", R.layout.changelog_title), + ITEM("item", "text", R.layout.changelog_content); + + companion object { + val values = values() + } + + /** + * Returns true if tag matches; false otherwise + */ + fun add(parser: XmlResourceParser, list: MutableList<Pair<String, ChangelogType>>): Boolean { + if (parser.name != tag) return false + if (parser.getAttributeValue(null, attr).isNotBlank()) + list.add(Pair(parser.getAttributeValue(null, attr), this)) + return true + } +} + diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/FragmentUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/FragmentUtils.kt new file mode 100644 index 00000000..cd638068 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/FragmentUtils.kt @@ -0,0 +1,15 @@ +package com.pitchedapps.frost.utils + +import android.os.Bundle +import android.support.v4.app.Fragment + +/** + * Created by Allan Wang on 2017-05-29. + */ + +fun Fragment.withBundle(creator: (Bundle) -> Unit): Fragment { + val bundle = Bundle() + creator.invoke(bundle) + this.arguments = bundle + return this +}
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Kotterknife.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Kotterknife.kt new file mode 100644 index 00000000..6e3b5c24 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Kotterknife.kt @@ -0,0 +1,137 @@ +package com.pitchedapps.frost.utils + +/** + * Created by Allan Wang on 2017-05-29. + * + * Courtesy of Jake Wharton + * + * https://github.com/JakeWharton/kotterknife/blob/master/src/main/kotlin/kotterknife/ButterKnife.kt + */ +import android.app.Activity +import android.app.Dialog +import android.app.DialogFragment +import android.app.Fragment +import android.support.v7.widget.RecyclerView.ViewHolder +import android.view.View +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty +import android.support.v4.app.DialogFragment as SupportDialogFragment +import android.support.v4.app.Fragment as SupportFragment + +public fun <V : View> View.bindView(id: Int) + : ReadOnlyProperty<View, V> = required(id, viewFinder) +public fun <V : View> Activity.bindView(id: Int) + : ReadOnlyProperty<Activity, V> = required(id, viewFinder) +public fun <V : View> Dialog.bindView(id: Int) + : ReadOnlyProperty<Dialog, V> = required(id, viewFinder) +public fun <V : View> DialogFragment.bindView(id: Int) + : ReadOnlyProperty<DialogFragment, V> = required(id, viewFinder) +public fun <V : View> SupportDialogFragment.bindView(id: Int) + : ReadOnlyProperty<SupportDialogFragment, V> = required(id, viewFinder) +public fun <V : View> Fragment.bindView(id: Int) + : ReadOnlyProperty<Fragment, V> = required(id, viewFinder) +public fun <V : View> SupportFragment.bindView(id: Int) + : ReadOnlyProperty<SupportFragment, V> = required(id, viewFinder) +public fun <V : View> ViewHolder.bindView(id: Int) + : ReadOnlyProperty<ViewHolder, V> = required(id, viewFinder) + +public fun <V : View> View.bindOptionalView(id: Int) + : ReadOnlyProperty<View, V?> = optional(id, viewFinder) +public fun <V : View> Activity.bindOptionalView(id: Int) + : ReadOnlyProperty<Activity, V?> = optional(id, viewFinder) +public fun <V : View> Dialog.bindOptionalView(id: Int) + : ReadOnlyProperty<Dialog, V?> = optional(id, viewFinder) +public fun <V : View> DialogFragment.bindOptionalView(id: Int) + : ReadOnlyProperty<DialogFragment, V?> = optional(id, viewFinder) +public fun <V : View> SupportDialogFragment.bindOptionalView(id: Int) + : ReadOnlyProperty<SupportDialogFragment, V?> = optional(id, viewFinder) +public fun <V : View> Fragment.bindOptionalView(id: Int) + : ReadOnlyProperty<Fragment, V?> = optional(id, viewFinder) +public fun <V : View> SupportFragment.bindOptionalView(id: Int) + : ReadOnlyProperty<SupportFragment, V?> = optional(id, viewFinder) +public fun <V : View> ViewHolder.bindOptionalView(id: Int) + : ReadOnlyProperty<ViewHolder, V?> = optional(id, viewFinder) + +public fun <V : View> View.bindViews(vararg ids: Int) + : ReadOnlyProperty<View, List<V>> = required(ids, viewFinder) +public fun <V : View> Activity.bindViews(vararg ids: Int) + : ReadOnlyProperty<Activity, List<V>> = required(ids, viewFinder) +public fun <V : View> Dialog.bindViews(vararg ids: Int) + : ReadOnlyProperty<Dialog, List<V>> = required(ids, viewFinder) +public fun <V : View> DialogFragment.bindViews(vararg ids: Int) + : ReadOnlyProperty<DialogFragment, List<V>> = required(ids, viewFinder) +public fun <V : View> SupportDialogFragment.bindViews(vararg ids: Int) + : ReadOnlyProperty<SupportDialogFragment, List<V>> = required(ids, viewFinder) +public fun <V : View> Fragment.bindViews(vararg ids: Int) + : ReadOnlyProperty<Fragment, List<V>> = required(ids, viewFinder) +public fun <V : View> SupportFragment.bindViews(vararg ids: Int) + : ReadOnlyProperty<SupportFragment, List<V>> = required(ids, viewFinder) +public fun <V : View> ViewHolder.bindViews(vararg ids: Int) + : ReadOnlyProperty<ViewHolder, List<V>> = required(ids, viewFinder) + +public fun <V : View> View.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<View, List<V>> = optional(ids, viewFinder) +public fun <V : View> Activity.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<Activity, List<V>> = optional(ids, viewFinder) +public fun <V : View> Dialog.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<Dialog, List<V>> = optional(ids, viewFinder) +public fun <V : View> DialogFragment.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<DialogFragment, List<V>> = optional(ids, viewFinder) +public fun <V : View> SupportDialogFragment.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<SupportDialogFragment, List<V>> = optional(ids, viewFinder) +public fun <V : View> Fragment.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<Fragment, List<V>> = optional(ids, viewFinder) +public fun <V : View> SupportFragment.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<SupportFragment, List<V>> = optional(ids, viewFinder) +public fun <V : View> ViewHolder.bindOptionalViews(vararg ids: Int) + : ReadOnlyProperty<ViewHolder, List<V>> = optional(ids, viewFinder) + +private val View.viewFinder: View.(Int) -> View? + get() = { findViewById(it) } +private val Activity.viewFinder: Activity.(Int) -> View? + get() = { findViewById(it) } +private val Dialog.viewFinder: Dialog.(Int) -> View? + get() = { findViewById(it) } +private val DialogFragment.viewFinder: DialogFragment.(Int) -> View? + get() = { dialog.findViewById(it) } +private val SupportDialogFragment.viewFinder: SupportDialogFragment.(Int) -> View? + get() = { dialog.findViewById(it) } +private val Fragment.viewFinder: Fragment.(Int) -> View? + get() = { view.findViewById(it) } +private val SupportFragment.viewFinder: SupportFragment.(Int) -> View? + get() = { view!!.findViewById(it) } +private val ViewHolder.viewFinder: ViewHolder.(Int) -> View? + get() = { itemView.findViewById(it) } + +private fun viewNotFound(id:Int, desc: KProperty<*>): Nothing = + throw IllegalStateException("View ID $id for '${desc.name}' not found.") + +@Suppress("UNCHECKED_CAST") +private fun <T, V : View> required(id: Int, finder: T.(Int) -> View?) + = Lazy { t: T, desc -> t.finder(id) as V? ?: viewNotFound(id, desc) } + +@Suppress("UNCHECKED_CAST") +private fun <T, V : View> optional(id: Int, finder: T.(Int) -> View?) + = Lazy { t: T, desc -> t.finder(id) as V? } + +@Suppress("UNCHECKED_CAST") +private fun <T, V : View> required(ids: IntArray, finder: T.(Int) -> View?) + = Lazy { t: T, desc -> ids.map { t.finder(it) as V? ?: viewNotFound(it, desc) } } + +@Suppress("UNCHECKED_CAST") +private fun <T, V : View> optional(ids: IntArray, finder: T.(Int) -> View?) + = Lazy { t: T, desc -> ids.map { t.finder(it) as V? }.filterNotNull() } + +// Like Kotlin's lazy delegate but the initializer gets the target and metadata passed to it +private class Lazy<T, V>(private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty<T, V> { + private object EMPTY + private var value: Any? = EMPTY + + override fun getValue(thisRef: T, property: KProperty<*>): V { + if (value == EMPTY) { + value = initializer(thisRef, property) + } + @Suppress("UNCHECKED_CAST") + return value as V + } +}
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt new file mode 100644 index 00000000..279d595e --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt @@ -0,0 +1,12 @@ +package com.pitchedapps.frost.utils + +/** + * Created by Allan Wang on 2017-05-28. + */ +class L { + companion object { + val TAG = "Frost" + fun e(s: String) = android.util.Log.e(com.pitchedapps.frost.utils.L.Companion.TAG, s) + fun d(s: String) = android.util.Log.d(com.pitchedapps.frost.utils.L.Companion.TAG, s) + } +}
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt new file mode 100644 index 00000000..c98fd5a5 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt @@ -0,0 +1,30 @@ +package com.pitchedapps.frost.utils + +import com.pitchedapps.frost.FrostApp + +/** + * Created by Allan Wang on 2017-05-28. + */ +val prefs: Prefs by lazy { FrostApp.prefs } + +class Prefs(c: android.content.Context) { + private companion object { + val PREFERENCE_NAME = "${com.pitchedapps.frost.BuildConfig.APPLICATION_ID}.prefs" + val LAST_ACTIVE = "last_active" + } + + var lastActive: Long + get() = prefs.getLong(com.pitchedapps.frost.utils.Prefs.Companion.LAST_ACTIVE, -1) + set(value) = set(com.pitchedapps.frost.utils.Prefs.Companion.LAST_ACTIVE, System.currentTimeMillis()) + + init { + lastActive = 0 + } + + private val prefs: android.content.SharedPreferences by lazy { c.getSharedPreferences(com.pitchedapps.frost.utils.Prefs.Companion.PREFERENCE_NAME, android.content.Context.MODE_PRIVATE) } + + private fun set(key: String, value: Boolean) = prefs.edit().putBoolean(key, value).apply() + private fun set(key: String, value: Int) = prefs.edit().putInt(key, value).apply() + private fun set(key: String, value: Long) = prefs.edit().putLong(key, value).apply() + private fun set(key: String, value: String) = prefs.edit().putString(key, value).apply() +}
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt new file mode 100644 index 00000000..bbf0e1f0 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -0,0 +1,11 @@ +package com.pitchedapps.frost.utils + +import android.content.res.Resources + +/** + * Created by Allan Wang on 2017-05-28. + */ +object Utils { + fun dpToPx(dp: Int) = (dp * android.content.res.Resources.getSystem().displayMetrics.density).toInt() + fun pxToDp(px:Int) = (px / android.content.res.Resources.getSystem().displayMetrics.density).toInt() +}
\ No newline at end of file |