Skip to content

Commit 3a19dd6

Browse files
Merge pull request #341 from Ayush0Chaudhary/feature/daily-task-limit
Implement daily task limit
2 parents 4d9ca0d + eb281dc commit 3a19dd6

File tree

2 files changed

+77
-44
lines changed

2 files changed

+77
-44
lines changed

app/src/main/java/com/blurr/voice/MainActivity.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,8 +457,11 @@ class MainActivity : AppCompatActivity(), PaywallResultHandler {
457457
goProButton.visibility = View.GONE
458458

459459
} else if (tasksLeft != null && tasksLeft >= 0) {
460-
461-
tasksRemainingTextView.text = "You have $tasksLeft free tasks remaining."
460+
if (tasksLeft > 0) {
461+
tasksRemainingTextView.text = "You have $tasksLeft free tasks remaining today."
462+
} else {
463+
tasksRemainingTextView.text = "You have 0 free tasks left for today."
464+
}
462465
tasksRemainingTextView.visibility = View.VISIBLE
463466
goProButton.visibility = View.VISIBLE
464467

@@ -471,7 +474,8 @@ class MainActivity : AppCompatActivity(), PaywallResultHandler {
471474
} else {
472475
tasksRemainingTextView.visibility = View.GONE
473476
increaseLimitsLink.visibility = View.GONE
474-
goProButton.visibility = View.VISIBLE }
477+
goProButton.visibility = View.VISIBLE
478+
}
475479
}
476480
}
477481

app/src/main/java/com/blurr/voice/utilities/FreemiumManager.kt

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,22 @@ package com.blurr.voice.utilities
22

33
import android.util.Log
44
import com.google.firebase.Firebase
5+
import com.google.firebase.Timestamp
56
import com.google.firebase.auth.auth
67
import com.google.firebase.firestore.FieldValue
78
import com.google.firebase.firestore.firestore
89
import com.revenuecat.purchases.Purchases
910
import com.revenuecat.purchases.awaitCustomerInfo
10-
1111
import kotlinx.coroutines.tasks.await
12+
import java.util.Calendar
1213

1314
class FreemiumManager {
1415

1516
private val db = Firebase.firestore
1617
private val auth = Firebase.auth
1718

1819
companion object {
19-
const val FREE_PLAN_TASK_LIMIT = 100 // Set your free task limit here
20+
const val DAILY_TASK_LIMIT = 100 // Set your daily task limit here
2021
}
2122

2223
private suspend fun isUserSubscribed(): Boolean {
@@ -29,28 +30,61 @@ class FreemiumManager {
2930
}
3031
}
3132

32-
/**
33-
* Checks if a user document exists in Firestore. If not, creates one with
34-
* the default free plan values. This should be called upon successful login.
35-
*/
33+
private fun isSameDay(timestamp: Timestamp): Boolean {
34+
val calendar1 = Calendar.getInstance()
35+
calendar1.time = timestamp.toDate()
36+
val calendar2 = Calendar.getInstance() // Current time
37+
38+
return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) &&
39+
calendar1.get(Calendar.DAY_OF_YEAR) == calendar2.get(Calendar.DAY_OF_YEAR)
40+
}
41+
42+
private suspend fun resetDailyTasksIfNeeded(uid: String) {
43+
val userDocRef = db.collection("users").document(uid)
44+
try {
45+
db.runTransaction { transaction ->
46+
val snapshot = transaction.get(userDocRef)
47+
val lastReset = snapshot.getTimestamp("tasksResetDate")
48+
49+
if (lastReset == null || !isSameDay(lastReset)) {
50+
Log.d("FreemiumManager", "New day detected. Resetting tasks for user $uid.")
51+
transaction.update(userDocRef, "tasksRemaining", DAILY_TASK_LIMIT)
52+
transaction.update(userDocRef, "tasksResetDate", FieldValue.serverTimestamp())
53+
}
54+
}.await()
55+
} catch (e: Exception) {
56+
Log.e("FreemiumManager", "Error in daily task reset transaction", e)
57+
}
58+
}
59+
3660
suspend fun provisionUserIfNeeded() {
37-
val currentUser = auth.currentUser ?: return // Should not be null if called after login
61+
val currentUser = auth.currentUser ?: return
3862
val userDocRef = db.collection("users").document(currentUser.uid)
3963

4064
try {
4165
val document = userDocRef.get().await()
4266
if (!document.exists()) {
43-
Log.d("FreemiumManager", "User document does not exist for UID ${currentUser.uid}. Provisioning new user.")
67+
Log.d("FreemiumManager", "Provisioning new user: ${currentUser.uid}")
4468
val newUser = hashMapOf(
4569
"email" to currentUser.email,
4670
"plan" to "free",
47-
"tasksRemaining" to FREE_PLAN_TASK_LIMIT,
48-
"createdAt" to FieldValue.serverTimestamp()
71+
"tasksRemaining" to DAILY_TASK_LIMIT,
72+
"createdAt" to FieldValue.serverTimestamp(),
73+
"tasksResetDate" to FieldValue.serverTimestamp() // Set initial reset date
4974
)
5075
userDocRef.set(newUser).await()
51-
Log.d("FreemiumManager", "Successfully provisioned user.")
5276
} else {
53-
Log.d("FreemiumManager", "User document already exists for UID ${currentUser.uid}.")
77+
// For existing users, check if they need the new daily limit fields
78+
if (!document.contains("tasksResetDate")) {
79+
Log.d("FreemiumManager", "Migrating existing user ${currentUser.uid} to daily limit system.")
80+
userDocRef.update(mapOf(
81+
"tasksRemaining" to DAILY_TASK_LIMIT,
82+
"tasksResetDate" to FieldValue.serverTimestamp()
83+
)).await()
84+
} else {
85+
// This is a good place to reset their tasks if it's a new day
86+
resetDailyTasksIfNeeded(currentUser.uid)
87+
}
5488
}
5589
} catch (e: Exception) {
5690
Log.e("FreemiumManager", "Error provisioning user", e)
@@ -60,56 +94,51 @@ class FreemiumManager {
6094
suspend fun getTasksRemaining(): Long? {
6195
if (isUserSubscribed()) return Long.MAX_VALUE
6296
val currentUser = auth.currentUser ?: return null
97+
resetDailyTasksIfNeeded(currentUser.uid) // Ensure tasks are up-to-date before fetching
6398
return try {
6499
val document = db.collection("users").document(currentUser.uid).get().await()
65100
document.getLong("tasksRemaining")
66101
} catch (e: Exception) {
67102
Log.e("FreemiumManager", "Error fetching tasks remaining", e)
68-
null // Return null on error so the UI can handle it
103+
null
69104
}
70105
}
71-
/**
72-
* Checks if the user can perform a task.
73-
* This is a simple read operation.
74-
* @return true if tasksRemaining > 0, false otherwise.
75-
*/
106+
76107
suspend fun canPerformTask(): Boolean {
77108
if (isUserSubscribed()) return true
78-
79-
val currentUser = auth.currentUser
80-
if (currentUser == null) {
81-
Log.w("FreemiumManager", "Cannot check task count, user is not logged in.")
82-
return false
83-
}
109+
val currentUser = auth.currentUser ?: return false
110+
resetDailyTasksIfNeeded(currentUser.uid) // Crucial check before verifying task count
84111

85112
return try {
86113
val document = db.collection("users").document(currentUser.uid).get().await()
87114
val tasksRemaining = document.getLong("tasksRemaining") ?: 0
88-
Log.d("FreemiumManager", "User has $tasksRemaining tasks remaining.")
115+
Log.d("FreemiumManager", "User has $tasksRemaining tasks remaining today.")
89116
tasksRemaining > 0
90117
} catch (e: Exception) {
91118
Log.e("FreemiumManager", "Error fetching user task count", e)
92-
false // Fail safely, preventing task execution on error
119+
false
93120
}
94121
}
95122

96-
/**
97-
* Decrements the user's task count by 1.
98-
* Uses an atomic increment operation for safety.
99-
* This is a "fire and forget" call, we don't block the UI for it.
100-
*/
101123
suspend fun decrementTaskCount() {
102124
if (isUserSubscribed()) return
103-
104125
val currentUser = auth.currentUser ?: return
105-
db.collection("users").document(currentUser.uid)
106-
.update("tasksRemaining", FieldValue.increment(-1))
107-
.addOnSuccessListener {
108-
Log.d("FreemiumManager", "Successfully decremented task count for user ${currentUser.uid}.")
109-
}
110-
.addOnFailureListener { e ->
111-
Log.e("FreemiumManager", "Failed to decrement task count.", e)
112-
// You might want to add logic here to retry or log this failure more robustly
113-
}
126+
127+
val userDocRef = db.collection("users").document(currentUser.uid)
128+
resetDailyTasksIfNeeded(currentUser.uid) // Ensure we don't decrement on a stale count
129+
130+
// Decrement only if tasks are remaining
131+
val tasksRemaining = getTasksRemaining()
132+
if (tasksRemaining != null && tasksRemaining > 0) {
133+
userDocRef.update("tasksRemaining", FieldValue.increment(-1))
134+
.addOnSuccessListener {
135+
Log.d("FreemiumManager", "Successfully decremented task count for user ${currentUser.uid}.")
136+
}
137+
.addOnFailureListener { e ->
138+
Log.e("FreemiumManager", "Failed to decrement task count.", e)
139+
}
140+
} else {
141+
Log.w("FreemiumManager", "Attempted to decrement task count, but none were left.")
142+
}
114143
}
115144
}

0 commit comments

Comments
 (0)