Adds blog tips button

blinds
Laurent 5 years ago
parent 4b1f3abc4e
commit b448dfaab7
  1. 2
      app/build.gradle
  2. 5
      app/src/main/AndroidManifest.xml
  3. 49
      app/src/main/java/net/pokeranalytics/android/api/BlogPostApi.kt
  4. 13
      app/src/main/java/net/pokeranalytics/android/model/blogpost/BlogPost.kt
  5. 6
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  6. 72
      app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt
  7. 10
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/SettingsRow.kt
  8. 64
      app/src/main/java/net/pokeranalytics/android/util/Preferences.kt
  9. 1
      app/src/main/java/net/pokeranalytics/android/util/URL.kt
  10. 9
      app/src/main/res/drawable/ic_public.xml
  11. 19
      app/src/main/res/layout/fragment_feed.xml
  12. 3
      app/src/main/res/values/strings.xml

@ -115,7 +115,7 @@ dependencies {
// Android // Android
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.3.1' implementation 'androidx.core:core-ktx:1.3.1'
implementation 'com.google.android.material:material:1.2.1' implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.work:work-runtime-ktx:2.4.0' implementation 'androidx.work:work-runtime-ktx:2.4.0'

@ -178,6 +178,11 @@
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.modules.blogposts.BlogPostActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<!-- No screenOrientation="portrait" to fix Oreo crash --> <!-- No screenOrientation="portrait" to fix Oreo crash -->
<activity <activity
android:name="net.pokeranalytics.android.ui.activity.ColorPickerActivity" android:name="net.pokeranalytics.android.ui.activity.ColorPickerActivity"

@ -0,0 +1,49 @@
package net.pokeranalytics.android.api
import android.content.Context
import com.android.volley.Request
import com.android.volley.toolbox.JsonArrayRequest
import com.android.volley.toolbox.Volley
import org.json.JSONArray
import timber.log.Timber
data class BlogPost(var id: Int, var content: String)
private fun JSONArray.toBlogPosts(): List<BlogPost> {
val posts = mutableListOf<BlogPost>()
(0 until this.length()).forEach { index ->
val jo = this.getJSONObject(index)
val post = BlogPost(jo.getInt("id"), jo.getJSONObject("content").getString("rendered"))
posts.add(post)
}
return posts
}
class BlogPostApi {
companion object {
private const val tipsLastPostsURL = "https://www.poker-analytics.net/blog/wp-json/wp/v2/posts/?categories=109\n"
fun getLatestPosts(context: Context, callback: (List<BlogPost>) -> (Unit)) {
val queue = Volley.newRequestQueue(context)
val jsonObjectRequest = JsonArrayRequest(
Request.Method.GET, tipsLastPostsURL, null,
{ response ->
// Timber.d("posts = $response")
callback(response.toBlogPosts())
},
{ error ->
Timber.w("Error while retrieving blog posts: $error")
}
)
queue.add(jsonObjectRequest)
}
}
}

@ -0,0 +1,13 @@
package net.pokeranalytics.android.model.blogpost
import com.google.gson.annotations.SerializedName
class BlogPost {
@SerializedName("id")
var id: Int = 0
@SerializedName("level")
var content: String = ""
}

@ -153,6 +153,7 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
override fun boolForRow(row: RowRepresentable): Boolean { override fun boolForRow(row: RowRepresentable): Boolean {
return when (row) { return when (row) {
SettingsRow.STOP_NOTIFICATION -> Preferences.showStopNotifications(requireContext()) SettingsRow.STOP_NOTIFICATION -> Preferences.showStopNotifications(requireContext())
SettingsRow.SHOULD_SHOW_BLOG_TIPS -> Preferences.shouldShowBlogTips(requireContext())
else -> false else -> false
} }
} }
@ -183,6 +184,7 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
3 -> parentActivity?.openUrl(URL.FACEBOOK.value) 3 -> parentActivity?.openUrl(URL.FACEBOOK.value)
} }
} }
SettingsRow.BLOG_TIPS -> parentActivity?.openUrl(URL.BLOG_TIPS.value)
SettingsRow.POKER_RUMBLE -> parentActivity?.openUrl(URL.POKER_RUMBLE.value) SettingsRow.POKER_RUMBLE -> parentActivity?.openUrl(URL.POKER_RUMBLE.value)
SettingsRow.DISCORD -> parentActivity?.openUrl(URL.DISCORD.value) SettingsRow.DISCORD -> parentActivity?.openUrl(URL.DISCORD.value)
SettingsRow.PRIVACY_POLICY -> parentActivity?.openUrl(URL.PRIVACY_POLICY.value) SettingsRow.PRIVACY_POLICY -> parentActivity?.openUrl(URL.PRIVACY_POLICY.value)
@ -223,6 +225,10 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
} }
Preferences.setShowStopNotifications(show, requireContext()) Preferences.setShowStopNotifications(show, requireContext())
} }
SettingsRow.SHOULD_SHOW_BLOG_TIPS -> {
val show = value as Boolean
Preferences.showBlogTips(show, requireContext())
}
else -> {} else -> {}
} }
} }

@ -9,12 +9,15 @@ import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.android.billingclient.api.Purchase import com.android.billingclient.api.Purchase
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.badge.BadgeUtils
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.Sort import io.realm.Sort
import io.realm.kotlin.where import io.realm.kotlin.where
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.api.BlogPostApi
import net.pokeranalytics.android.databinding.FragmentFeedBinding import net.pokeranalytics.android.databinding.FragmentFeedBinding
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
@ -25,6 +28,7 @@ import net.pokeranalytics.android.model.realm.handhistory.HandHistory
import net.pokeranalytics.android.ui.activity.BillingActivity import net.pokeranalytics.android.ui.activity.BillingActivity
import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.activity.components.RequestCode
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.extensions.openUrl
import net.pokeranalytics.android.ui.fragment.components.FilterableFragment import net.pokeranalytics.android.ui.fragment.components.FilterableFragment
import net.pokeranalytics.android.ui.modules.data.EditableDataActivity import net.pokeranalytics.android.ui.modules.data.EditableDataActivity
import net.pokeranalytics.android.ui.modules.datalist.DataListActivity import net.pokeranalytics.android.ui.modules.datalist.DataListActivity
@ -36,6 +40,7 @@ import net.pokeranalytics.android.ui.modules.session.SessionActivity
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.URL
import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.PurchaseListener import net.pokeranalytics.android.util.billing.PurchaseListener
import net.pokeranalytics.android.util.extensions.count import net.pokeranalytics.android.util.extensions.count
@ -77,6 +82,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
private var selectedTransaction: Transaction? = null private var selectedTransaction: Transaction? = null
private var selectedTransactionPosition: Int = -1 private var selectedTransactionPosition: Int = -1
private var badgeDrawable: BadgeDrawable? = null
override val observedEntities: List<Class<out RealmModel>> = override val observedEntities: List<Class<out RealmModel>> =
listOf(Session::class.java, Transaction::class.java, HandHistory::class.java) listOf(Session::class.java, Transaction::class.java, HandHistory::class.java)
@ -121,7 +128,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
if (v.id == R.id.menuRecyclerView) { if (v.id == R.id.menuRecyclerView) {
activity?.menuInflater?.inflate(R.menu.menu_session, menu) activity?.menuInflater?.inflate(R.menu.menu_session, menu)
} }
} }
override fun onRowLongClick(itemView: View, row: RowRepresentable, position: Int) { override fun onRowLongClick(itemView: View, row: RowRepresentable, position: Int) {
@ -184,10 +190,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
} }
override fun onDestroy() {
super.onDestroy()
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
AppGuard.unregisterListener(this) AppGuard.unregisterListener(this)
@ -268,6 +270,27 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
} }
} }
this.view?.viewTreeObserver?.addOnGlobalLayoutListener {
Timber.d(">>> addOnGlobalLayoutListener called")
retrieveLatestBlogPosts() // attempt to retrieve blog tips on display
}
displayPostButton()
binding.postButton.setOnClickListener {
Preferences.setBlogTipsTapped(requireContext())
parentActivity?.openUrl(URL.BLOG_TIPS.value)
displayPostButton()
}
binding.postButton.viewTreeObserver.addOnGlobalLayoutListener {
val badgeDrawable = BadgeDrawable.create(requireContext())
BadgeUtils.attachBadgeDrawable(badgeDrawable, binding.postButton)
// badgeDrawable.number = 2
badgeDrawable.horizontalOffset = 30
badgeDrawable.verticalOffset = 20
this.badgeDrawable = badgeDrawable
}
// Tabs // Tabs
binding.tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { binding.tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) { override fun onTabSelected(tab: TabLayout.Tab) {
@ -379,9 +402,9 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
handHistoryFilter?.results() ?: run { getRealm().where<HandHistory>().findAll() } handHistoryFilter?.results() ?: run { getRealm().where<HandHistory>().findAll() }
this.realmHandHistories = this.realmHandHistories.sort("date", Sort.DESCENDING) this.realmHandHistories = this.realmHandHistories.sort("date", Sort.DESCENDING)
this.realmHandHistories.forEach { // this.realmHandHistories.forEach {
Timber.d("date = ${it.date}, year=${it.year}, month = ${it.month}, day = ${it.dayOfMonth}") // Timber.d("date = ${it.date}, year=${it.year}, month = ${it.month}, day = ${it.dayOfMonth}")
} // }
var hhDistinctDates = handHistoryFilter?.results("year", "month", "dayOfMonth") var hhDistinctDates = handHistoryFilter?.results("year", "month", "dayOfMonth")
?: getRealm().where<HandHistory>().distinct("year", "month", "dayOfMonth").findAll() ?: getRealm().where<HandHistory>().distinct("year", "month", "dayOfMonth").findAll()
@ -557,4 +580,37 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
this.showSubscriptionButton() this.showSubscriptionButton()
} }
private fun retrieveLatestBlogPosts() {
val now = Date().time
if (true) {
// if (Preferences.getLastBlogTipsRetrievalDate(requireContext()) + 24 * 3600 * 1000 < now) {
BlogPostApi.getLatestPosts(requireContext()) { posts ->
Preferences.setLastBlogTipsRetrievalDate(now, requireContext())
var count = 0
if (posts.isNotEmpty()) {
Preferences.setLatestRetrievedBlogPostId(posts.first().id, requireContext())
val id = Preferences.getLatestDisplayedBlogPostId(requireContext())
count = posts.count { it.id > id }
}
displayPostButton(count)
}
}
}
private fun displayPostButton(newCount: Int = 0) {
var show = false
if (Preferences.shouldShowBlogTips(requireContext()) && newCount > 0) {
show = true
this.badgeDrawable?.number = newCount
}
this.binding.postButton.isVisible = show
this.badgeDrawable?.isVisible = show
}
} }

@ -29,6 +29,8 @@ enum class SettingsRow : RowRepresentable {
// Follow // Follow
FOLLOW_US, FOLLOW_US,
POKER_RUMBLE, POKER_RUMBLE,
SHOULD_SHOW_BLOG_TIPS,
BLOG_TIPS,
// Preferences // Preferences
LANGUAGE, LANGUAGE,
@ -70,10 +72,10 @@ enum class SettingsRow : RowRepresentable {
} }
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information))
rows.addAll(arrayListOf(SUBSCRIPTION, VERSION, RATE_APP, CONTACT_US, BUG_REPORT, DISCORD)) rows.addAll(arrayListOf(SUBSCRIPTION, VERSION, RATE_APP, CONTACT_US, BUG_REPORT))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.follow_us)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.follow_us))
rows.addAll(arrayListOf(FOLLOW_US)) rows.addAll(arrayListOf(FOLLOW_US, DISCORD, BLOG_TIPS, SHOULD_SHOW_BLOG_TIPS))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.preferences)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.preferences))
rows.addAll(arrayListOf(CURRENCY)) rows.addAll(arrayListOf(CURRENCY))
@ -116,6 +118,8 @@ enum class SettingsRow : RowRepresentable {
PRIVACY_POLICY -> R.string.privacy_policy PRIVACY_POLICY -> R.string.privacy_policy
TERMS_OF_USE -> R.string.terms_of_use TERMS_OF_USE -> R.string.terms_of_use
FOLLOW_US -> R.string.follow_us FOLLOW_US -> R.string.follow_us
BLOG_TIPS -> R.string.blog_tips
SHOULD_SHOW_BLOG_TIPS -> R.string.show_blog_tips
LANGUAGE -> R.string.language LANGUAGE -> R.string.language
CURRENCY -> R.string.currency CURRENCY -> R.string.currency
EXPORT_CSV_SESSIONS -> R.string.sessions_csv EXPORT_CSV_SESSIONS -> R.string.sessions_csv
@ -135,7 +139,7 @@ enum class SettingsRow : RowRepresentable {
VERSION, SUBSCRIPTION -> RowViewType.TITLE_VALUE.ordinal VERSION, SUBSCRIPTION -> RowViewType.TITLE_VALUE.ordinal
LANGUAGE, CURRENCY -> RowViewType.TITLE_VALUE_ARROW.ordinal LANGUAGE, CURRENCY -> RowViewType.TITLE_VALUE_ARROW.ordinal
FOLLOW_US -> RowViewType.ROW_FOLLOW_US.ordinal FOLLOW_US -> RowViewType.ROW_FOLLOW_US.ordinal
STOP_NOTIFICATION -> RowViewType.TITLE_SWITCH.ordinal STOP_NOTIFICATION, SHOULD_SHOW_BLOG_TIPS -> RowViewType.TITLE_SWITCH.ordinal
STOP_NOTIFICATION_MESSAGE -> RowViewType.INFO.ordinal STOP_NOTIFICATION_MESSAGE -> RowViewType.INFO.ordinal
else -> RowViewType.TITLE_ARROW.ordinal else -> RowViewType.TITLE_ARROW.ordinal
} }

@ -36,7 +36,11 @@ class Preferences {
SHOW_STOP_NOTIFICATIONS("showStopNotifications"), SHOW_STOP_NOTIFICATIONS("showStopNotifications"),
ADD_NEW_TRANSACTION_TYPES("addNewTransactionTypes"), ADD_NEW_TRANSACTION_TYPES("addNewTransactionTypes"),
SHOW_VILLAIN_CARDS("showVillainCards"), SHOW_VILLAIN_CARDS("showVillainCards"),
BANKROLL_RESULT_CAPTURE_TYPE("bankrollResultCaptureType_") BANKROLL_RESULT_CAPTURE_TYPE("bankrollResultCaptureType_"),
LATEST_BLOG_POST_ID_RETRIEVED("latestBlogPostIdRetrieved"),
LATEST_BLOG_POST_ID_DISPLAYED("latestBlogPostIdDisplayed"),
LAST_BLOG_TIPS_RETRIEVAL("lastBlogTipsRetrieval"),
SHOW_BLOG_TIPS("showBlogTips"),
} }
enum class FeedMessage { enum class FeedMessage {
@ -113,6 +117,29 @@ class Preferences {
return preferences.getBoolean(key.identifier, defaultValue ?: false) return preferences.getBoolean(key.identifier, defaultValue ?: false)
} }
private fun setInt(key: PreferenceKey, value: Int, context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.edit()
editor.putInt(key.identifier, value)
editor.apply()
}
private fun getInt(key: PreferenceKey, context: Context): Int {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getInt(key.identifier, -1)
}
private fun setLong(key: PreferenceKey, value: Long, context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.edit()
editor.putLong(key.identifier, value)
editor.apply()
}
private fun getLong(key: PreferenceKey, context: Context): Long {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getLong(key.identifier, 0L)
}
fun setShowVillainCards(show: Boolean, context: Context) { fun setShowVillainCards(show: Boolean, context: Context) {
setBoolean(Keys.SHOW_VILLAIN_CARDS, show, context) setBoolean(Keys.SHOW_VILLAIN_CARDS, show, context)
@ -213,7 +240,40 @@ class Preferences {
else -> ResultCaptureType.values()[ordinal] else -> ResultCaptureType.values()[ordinal]
} }
} }
}
fun setLatestRetrievedBlogPostId(id: Int, context: Context) {
setInt(Keys.LATEST_BLOG_POST_ID_RETRIEVED, id, context)
}
private fun getLatestRetrievedBlogPostId(context: Context): Int {
return getInt(Keys.LATEST_BLOG_POST_ID_RETRIEVED, context)
}
fun setBlogTipsTapped(context: Context) {
setInt(Keys.LATEST_BLOG_POST_ID_RETRIEVED, getLatestRetrievedBlogPostId(context), context)
}
fun getLatestDisplayedBlogPostId(context: Context): Long {
return getLong(Keys.LATEST_BLOG_POST_ID_DISPLAYED, context)
}
fun showBlogTips(show: Boolean, context: Context) {
setBoolean(Keys.SHOW_BLOG_TIPS, show, context)
}
fun shouldShowBlogTips(context: Context): Boolean {
return getBoolean(Keys.SHOW_BLOG_TIPS, context, true)
}
fun setLastBlogTipsRetrievalDate(date: Long, context: Context) {
setLong(Keys.LAST_BLOG_TIPS_RETRIEVAL, date, context)
}
fun getLastBlogTipsRetrievalDate(context: Context): Long {
return getLong(Keys.LAST_BLOG_TIPS_RETRIEVAL, context)
}
}
} }

@ -14,6 +14,7 @@ enum class URL(var value: String) {
INSTAGRAM("https://www.instagram.com/pokeranalytics"), INSTAGRAM("https://www.instagram.com/pokeranalytics"),
TWITTER("https://twitter.com/paapptweet"), TWITTER("https://twitter.com/paapptweet"),
FACEBOOK("https://www.facebook.com/171053452998758"), FACEBOOK("https://www.facebook.com/171053452998758"),
BLOG_TIPS("https://www.poker-analytics.net/blog/category/tips/#main"),
// Support // Support
SUPPORT_EMAIL("support@pokeranalytics.net"), SUPPORT_EMAIL("support@pokeranalytics.net"),

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"
android:fillColor="#000000"/>
</vector>

@ -104,7 +104,24 @@
android:transitionName="floating_action_button" android:transitionName="floating_action_button"
app:fabSize="normal" app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="@string/add_manually" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/postButton"
style="@style/PokerAnalyticsTheme.FloatingButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_public"
android:tint="@color/black"
android:transitionName="floating_action_button_blog_post"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:contentDescription="@string/posts" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/subscribe" android:id="@+id/subscribe"

@ -808,5 +808,8 @@
<string name="please_save_hand_history">Please save before sharing</string> <string name="please_save_hand_history">Please save before sharing</string>
<string name="contact_support">It looks like there is an issue here. Please contact the support to get help.</string> <string name="contact_support">It looks like there is an issue here. Please contact the support to get help.</string>
<string name="product_unavailable">Please wait for a second or retry in a moment...</string> <string name="product_unavailable">Please wait for a second or retry in a moment...</string>
<string name="posts">posts</string>
<string name="show_blog_tips">Show tips on front page</string>
<string name="blog_tips">App tips</string>
</resources> </resources>

Loading…
Cancel
Save