diff --git a/app/build.gradle b/app/build.gradle index 36a8454a78..76daea9f36 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "org.ole.planet.myplanet" minSdkVersion 26 targetSdkVersion 34 - versionCode 2107 - versionName "0.21.7" + versionCode 2124 + versionName "0.21.24" ndkVersion '21.3.6528147' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -208,7 +208,7 @@ dependencies { implementation "androidx.camera:camera-lifecycle:$camera_version" implementation "androidx.camera:camera-view:$camera_version" - def dagger_hilt_version = "2.52" + def dagger_hilt_version = "2.53" implementation "com.google.dagger:hilt-android:$dagger_hilt_version" kapt "com.google.dagger:hilt-android-compiler:$dagger_hilt_version" @@ -220,7 +220,7 @@ dependencies { implementation "com.github.bumptech.glide:glide:$glide_version" kapt "com.github.bumptech.glide:compiler:$glide_version" - def media3_version = "1.4.1" + def media3_version = "1.5.0" implementation "androidx.media3:media3-exoplayer:$media3_version" implementation "androidx.media3:media3-ui:$media3_version" implementation "androidx.media3:media3-common:$media3_version" @@ -230,7 +230,7 @@ dependencies { implementation "io.noties.markwon:image:$markwon_version" implementation "io.noties.markwon:html:$markwon_version" implementation "io.noties.markwon:ext-tables:$markwon_version" - implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.0.21")) + implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.1.0")) implementation 'com.github.chrisbanes:PhotoView:2.3.0' } diff --git a/app/src/main/assets/images/november_challenge.jpeg b/app/src/main/assets/images/november_challenge.jpeg deleted file mode 100644 index 885e65f056..0000000000 Binary files a/app/src/main/assets/images/november_challenge.jpeg and /dev/null differ diff --git a/app/src/main/java/org/ole/planet/myplanet/MainApplication.kt b/app/src/main/java/org/ole/planet/myplanet/MainApplication.kt index 8b622e538c..45d77600e1 100644 --- a/app/src/main/java/org/ole/planet/myplanet/MainApplication.kt +++ b/app/src/main/java/org/ole/planet/myplanet/MainApplication.kt @@ -121,8 +121,8 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks { suspend fun isServerReachable(urlString: String?): Boolean { return try { - if (urlString.isNullOrBlank()) return false - + if (urlString.isBlank()) return false + val formattedUrl = if (!urlString.startsWith("http://") && !urlString.startsWith("https://")) { "http://$urlString" } else { diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/courses/AdapterCourses.kt b/app/src/main/java/org/ole/planet/myplanet/ui/courses/AdapterCourses.kt index 83709f82c4..760cc284ed 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/courses/AdapterCourses.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/courses/AdapterCourses.kt @@ -139,8 +139,8 @@ class AdapterCourses(private val context: Context, private var courseList: List< holder.rowCourseBinding.title.text = course.courseTitle holder.rowCourseBinding.description.apply { text = course.description - val markdownContentWithLocalPaths = AdapterCourses.prependBaseUrlToImages( - course.description, "file://" + MainApplication.context.getExternalFilesDir(null) + "/ole/" + val markdownContentWithLocalPaths = prependBaseUrlToImages( + course.description, "file://${MainApplication.context.getExternalFilesDir(null)}/ole/" ) setMarkdownText(this, markdownContentWithLocalPaths) diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/courses/MyProgressFragment.kt b/app/src/main/java/org/ole/planet/myplanet/ui/courses/MyProgressFragment.kt index 83f0a3c3bd..88e1a86680 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/courses/MyProgressFragment.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/courses/MyProgressFragment.kt @@ -19,6 +19,7 @@ import org.ole.planet.myplanet.model.RealmExamQuestion import org.ole.planet.myplanet.model.RealmMyCourse import org.ole.planet.myplanet.model.RealmStepExam import org.ole.planet.myplanet.model.RealmSubmission +import org.ole.planet.myplanet.model.RealmUserModel import org.ole.planet.myplanet.service.UserProfileDbHandler class MyProgressFragment : Fragment() { @@ -111,5 +112,26 @@ class MyProgressFragment : Fragment() { } return null } + + fun countUsersWhoCompletedCourse(realm: Realm, courseId: String): Int { + var completedCount = 0 + val allUsers = realm.where(RealmUserModel::class.java).findAll() + + allUsers.forEach { user -> + val userId = user.id + val courses = RealmMyCourse.getMyCourseByUserId(userId, realm.where(RealmMyCourse::class.java).findAll()) + + val course = courses.find { it.courseId == courseId } + if (course != null) { + val steps = RealmMyCourse.getCourseSteps(realm, courseId) + val currentProgress = RealmCourseProgress.getCurrentProgress(steps, realm, userId, courseId) + + if (currentProgress == steps.size) { + completedCount++ + } + } + } + return completedCount + } } } diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/courses/TakeCourseFragment.kt b/app/src/main/java/org/ole/planet/myplanet/ui/courses/TakeCourseFragment.kt index b12fe54d35..14837fbb7c 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/courses/TakeCourseFragment.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/courses/TakeCourseFragment.kt @@ -33,15 +33,14 @@ import org.ole.planet.myplanet.service.UserProfileDbHandler import org.ole.planet.myplanet.utilities.DialogUtils.getAlertDialog import org.ole.planet.myplanet.utilities.Utilities import java.util.Locale +import kotlin.collections.isNotEmpty class TakeCourseFragment : Fragment(), ViewPager.OnPageChangeListener, View.OnClickListener { private lateinit var fragmentTakeCourseBinding: FragmentTakeCourseBinding lateinit var dbService: DatabaseService lateinit var mRealm: Realm - var courseId: String? = null private var currentCourse: RealmMyCourse? = null lateinit var steps: List - var userModel: RealmUserModel? = null var position = 0 private var currentStep = 0 @@ -250,12 +249,10 @@ class TakeCourseFragment : Fragment(), ViewPager.OnPageChangeListener, View.OnCl .equalTo("stepId", step?.id) .equalTo("type", "surveys") .findAll() - stepSurvey.any { survey -> - !existsSubmission(survey.id, "survey") - } + stepSurvey.any { survey -> !existsSubmission(mRealm, survey.id, "survey") } } - if (hasUnfinishedSurvey && courseId == "9517e3b45a5bb63e69bb8f269216974d") { + if (hasUnfinishedSurvey && courseId == "4e6b78800b6ad18b4e8b0e1e38a98cac") { fragmentTakeCourseBinding.finishStep.setOnClickListener { Toast.makeText(context, getString(R.string.please_complete_survey), Toast.LENGTH_SHORT).show() } } else { @@ -267,38 +264,39 @@ class TakeCourseFragment : Fragment(), ViewPager.OnPageChangeListener, View.OnCl } } - private fun existsSubmission(firstStepId: String?, submissionType: String): Boolean { - val questions = mRealm.where(RealmExamQuestion::class.java) - .equalTo("examId", firstStepId) - .findAll() - - var isPresent = false - if (questions != null && questions.isNotEmpty()) { - val examId = questions[0]?.examId - val isSubmitted = courseId?.let { courseId -> - val parentId = "$examId@$courseId" - mRealm.where(RealmSubmission::class.java) - .equalTo("userId", userModel?.id) - .equalTo("parentId", parentId) - .equalTo("type", submissionType) - .findFirst() != null - } == true - isPresent = isSubmitted - } - return isPresent - } - - private val isValidClickRight: Boolean - get() = fragmentTakeCourseBinding.viewPager2.adapter != null && fragmentTakeCourseBinding.viewPager2.currentItem < fragmentTakeCourseBinding.viewPager2.adapter?.itemCount!! - private val isValidClickLeft: Boolean - get() = fragmentTakeCourseBinding.viewPager2.adapter != null && fragmentTakeCourseBinding.viewPager2.currentItem > 0 + private val isValidClickRight: Boolean get() = fragmentTakeCourseBinding.viewPager2.adapter != null && fragmentTakeCourseBinding.viewPager2.currentItem < fragmentTakeCourseBinding.viewPager2.adapter?.itemCount!! + private val isValidClickLeft: Boolean get() = fragmentTakeCourseBinding.viewPager2.adapter != null && fragmentTakeCourseBinding.viewPager2.currentItem > 0 companion object { + var courseId: String? = null + var userModel: RealmUserModel? = null + @JvmStatic fun newInstance(b: Bundle?): TakeCourseFragment { val takeCourseFragment = TakeCourseFragment() takeCourseFragment.arguments = b return takeCourseFragment } + + fun existsSubmission(mRealm: Realm, firstStepId: String?, submissionType: String): Boolean { + val questions = mRealm.where(RealmExamQuestion::class.java) + .equalTo("examId", firstStepId) + .findAll() + + var isPresent = false + if (questions != null && questions.isNotEmpty()) { + val examId = questions[0]?.examId + val isSubmitted = courseId?.let { courseId -> + val parentId = "$examId@$courseId" + mRealm.where(RealmSubmission::class.java) + .equalTo("userId", userModel?.id) + .equalTo("parentId", parentId) + .equalTo("type", submissionType) + .findFirst() != null + } == true + isPresent = isSubmitted + } + return isPresent + } } } diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt b/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt index eeb3f8d28a..80d1e3d79d 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt @@ -41,10 +41,10 @@ import io.realm.RealmResults import kotlinx.coroutines.launch import org.json.JSONArray import org.ole.planet.myplanet.BuildConfig -import org.ole.planet.myplanet.MainApplication.Companion.context +import org.ole.planet.myplanet.MainApplication import org.ole.planet.myplanet.R import org.ole.planet.myplanet.base.BaseContainerFragment -import org.ole.planet.myplanet.base.BaseResourceFragment.Companion.getLibraryList +import org.ole.planet.myplanet.base.BaseResourceFragment import org.ole.planet.myplanet.callback.OnHomeItemClickListener import org.ole.planet.myplanet.databinding.ActivityDashboardBinding import org.ole.planet.myplanet.databinding.CustomTabBinding @@ -62,10 +62,10 @@ import org.ole.planet.myplanet.ui.SettingActivity import org.ole.planet.myplanet.ui.chat.ChatHistoryListFragment import org.ole.planet.myplanet.ui.community.CommunityTabFragment import org.ole.planet.myplanet.ui.courses.CoursesFragment -import org.ole.planet.myplanet.ui.courses.MyProgressFragment.Companion.fetchCourseData -import org.ole.planet.myplanet.ui.courses.MyProgressFragment.Companion.getCourseProgress -import org.ole.planet.myplanet.ui.dashboard.notification.NotificationsFragment +import org.ole.planet.myplanet.ui.courses.MyProgressFragment +import org.ole.planet.myplanet.ui.courses.TakeCourseFragment import org.ole.planet.myplanet.ui.dashboard.notification.NotificationListener +import org.ole.planet.myplanet.ui.dashboard.notification.NotificationsFragment import org.ole.planet.myplanet.ui.feedback.FeedbackListFragment import org.ole.planet.myplanet.ui.resources.ResourceDetailFragment import org.ole.planet.myplanet.ui.resources.ResourcesFragment @@ -231,7 +231,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } else { if (!doubleBackToExitPressedOnce) { doubleBackToExitPressedOnce = true - toast(context, getString(R.string.press_back_again_to_exit)) + toast(MainApplication.context, getString(R.string.press_back_again_to_exit)) Handler(Looper.getMainLooper()).postDelayed({ doubleBackToExitPressedOnce = false }, 2000) } else { val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container) @@ -245,12 +245,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } }) - val voiceCount = mRealm.where(RealmUserChallengeActions::class.java) - .equalTo("userId", user?.id) - .equalTo("actionType", "voice") - .findAll().count() - - val startTime = 1730408400 + val startTime = 1733011200000 val commVoiceResults = mRealm.where(RealmNews::class.java) .equalTo("userId", user?.id) .greaterThanOrEqualTo("time", startTime) @@ -307,10 +302,16 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N .map { getDateFromTimestamp(it.time) } .distinct() - val courseData = fetchCourseData(mRealm, user?.id) + val courseData = MyProgressFragment.fetchCourseData(mRealm, user?.id) + + val courseId = "4e6b78800b6ad18b4e8b0e1e38a98cac" + val progress = MyProgressFragment.getCourseProgress(courseData, courseId) - val courseId = "9517e3b45a5bb63e69bb8f269216974d" - val progress = getCourseProgress(courseData, courseId) + val hasUnfinishedSurvey = mRealm.where(RealmStepExam::class.java) + .equalTo("courseId", courseId) + .equalTo("type", "surveys") + .findAll() + .any { survey -> !TakeCourseFragment.existsSubmission(mRealm, survey.id, "survey") } val validUrls = listOf( "https://${BuildConfig.PLANET_GUATEMALA_URL}", @@ -323,7 +324,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N val today = LocalDate.now() if (user?.id?.startsWith("guest") == false) { - val endDate = LocalDate.of(today.year, 12, 1) + val endDate = LocalDate.of(today.year, 12, 31) if (today.isBefore(endDate)) { if (settings.getString("serverURL", "") in validUrls) { val course = mRealm.where(RealmMyCourse::class.java) @@ -339,20 +340,21 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } else { "Ingresa al curso $courseName completalo ($current de $max hecho)" } - challengeDialog(uniqueDates.size, courseStatus, allUniqueDates.size) + challengeDialog(uniqueDates.size, courseStatus, allUniqueDates.size, hasUnfinishedSurvey) } else { - challengeDialog(uniqueDates.size, "$courseName no iniciado", allUniqueDates.size) + challengeDialog(uniqueDates.size, "$courseName no iniciado", allUniqueDates.size, hasUnfinishedSurvey) } } } } } - fun challengeDialog(voiceCount: Int, courseStatus: String, allVoiceCount: Int) { + fun challengeDialog (voiceCount: Int, courseStatus: String, allVoiceCount: Int, hasUnfinishedSurvey: Boolean) { val voiceTaskDone = if (voiceCount >= 5) "✅" else "[ ]" val prereqsMet = courseStatus.contains("terminado", ignoreCase = true) && voiceCount >= 5 + var hasValidSync = false val syncTaskDone = if (prereqsMet) { - val hasValidSync = mRealm.where(RealmUserChallengeActions::class.java) + hasValidSync = mRealm.where(RealmUserChallengeActions::class.java) .equalTo("userId", user?.id) .equalTo("actionType", "sync") .count() > 0 @@ -370,30 +372,44 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N if (isCompleted && !hasShownCongrats) { editor.putBoolean("has_shown_congrats", true).apply() val markdownContent = """ - Ganancias totales: **$${calculateProgress(allVoiceCount)}** + Ingresos totales de la comunidad: **$${calculateCommunityProgress(allVoiceCount, hasUnfinishedSurvey)}** /$500 + + Tus ganancias totales: **$${calculateIndividualProgress(voiceCount, hasUnfinishedSurvey)}** /$11 ### ¡Felicidades! Reto Completado
""".trimIndent() - MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount) - .show(supportFragmentManager, "markdown_dialog") + MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount, hasUnfinishedSurvey).show(supportFragmentManager, "markdown_dialog") } else { - val voicesText = if (voiceCount > 0) { - "$voiceCount de 5 Voces diarias" + val cappedVoiceCount = minOf(voiceCount, 5) + val voicesText = if (cappedVoiceCount > 0) { + "$cappedVoiceCount de 5 Voces diarias" } else { "" } val markdownContent = """ - Ganancias totales: **$${calculateProgress(allVoiceCount)}** - ### $courseTaskDone
- ### $voiceTaskDone Comparte tu opinión en Nuestras Voces. $voicesText
+ Ingresos totales de la comunidad: **$${calculateCommunityProgress(allVoiceCount, hasUnfinishedSurvey)}** /$500 + + Tus ganancias totales: **$${calculateIndividualProgress(voiceCount, hasUnfinishedSurvey)}** /$11 + ### $courseTaskDone $1 por encuesta
+ ### $voiceTaskDone Comparte tu opinión en Nuestras Voces.[$2/voz] $voicesText
### $syncTaskDone Recuerda sincronizar la aplicación móvil.
""".trimIndent() - MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount) + MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount, hasUnfinishedSurvey) .show(supportFragmentManager, "markdown_dialog") } } - private fun calculateProgress(allVoiceCount: Int): Int { - return (allVoiceCount) * 5 + private fun calculateIndividualProgress(voiceCount: Int, hasUnfinishedSurvey: Boolean): Int { + val earnedDollarsVoice = minOf(voiceCount, 5) * 2 + val earnedDollarsSurvey = if (!hasUnfinishedSurvey) 1 else 0 + val total = earnedDollarsVoice + earnedDollarsSurvey + return total.coerceAtMost(500) + } + + private fun calculateCommunityProgress (allVoiceCount: Int, hasUnfinishedSurvey: Boolean): Int { + val earnedDollarsVoice = minOf(allVoiceCount, 5) * 2 + val earnedDollarsSurvey = if (!hasUnfinishedSurvey) 1 else 0 + val total = earnedDollarsVoice + earnedDollarsSurvey + return total.coerceAtMost(11) } private fun setupRealmListeners() { @@ -475,7 +491,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } private fun updateResourceNotification() { - val resourceCount = getLibraryList(mRealm, user?.id).size + val resourceCount = BaseResourceFragment.getLibraryList(mRealm, user?.id).size if (resourceCount > 0) { val existingNotification = mRealm.where(RealmNotification::class.java) .equalTo("userId", user?.id) diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt.lite b/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt.lite index 68feb330d7..ff850517f4 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt.lite +++ b/app/src/main/java/org/ole/planet/myplanet/ui/dashboard/DashboardActivity.kt.lite @@ -41,10 +41,10 @@ import io.realm.RealmResults import kotlinx.coroutines.launch import org.json.JSONArray import org.ole.planet.myplanet.BuildConfig -import org.ole.planet.myplanet.MainApplication.Companion.context +import org.ole.planet.myplanet.MainApplication import org.ole.planet.myplanet.R //import org.ole.planet.myplanet.base.BaseContainerFragment -import org.ole.planet.myplanet.base.BaseResourceFragment.Companion.getLibraryList +import org.ole.planet.myplanet.base.BaseResourceFragment import org.ole.planet.myplanet.callback.OnHomeItemClickListener import org.ole.planet.myplanet.databinding.ActivityDashboardBinding import org.ole.planet.myplanet.databinding.CustomTabBinding @@ -62,10 +62,10 @@ import org.ole.planet.myplanet.ui.SettingActivity import org.ole.planet.myplanet.ui.chat.ChatHistoryListFragment import org.ole.planet.myplanet.ui.community.CommunityTabFragment import org.ole.planet.myplanet.ui.courses.CoursesFragment -import org.ole.planet.myplanet.ui.courses.MyProgressFragment.Companion.fetchCourseData -import org.ole.planet.myplanet.ui.courses.MyProgressFragment.Companion.getCourseProgress -import org.ole.planet.myplanet.ui.dashboard.notification.NotificationsFragment +import org.ole.planet.myplanet.ui.courses.MyProgressFragment +import org.ole.planet.myplanet.ui.courses.TakeCourseFragment import org.ole.planet.myplanet.ui.dashboard.notification.NotificationListener +import org.ole.planet.myplanet.ui.dashboard.notification.NotificationsFragment import org.ole.planet.myplanet.ui.feedback.FeedbackListFragment import org.ole.planet.myplanet.ui.resources.ResourceDetailFragment import org.ole.planet.myplanet.ui.resources.ResourcesFragment @@ -231,7 +231,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } else { if (!doubleBackToExitPressedOnce) { doubleBackToExitPressedOnce = true - toast(context, getString(R.string.press_back_again_to_exit)) + toast(MainApplication.context, getString(R.string.press_back_again_to_exit)) Handler(Looper.getMainLooper()).postDelayed({ doubleBackToExitPressedOnce = false }, 2000) } else { // val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container) @@ -245,12 +245,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } }) - val voiceCount = mRealm.where(RealmUserChallengeActions::class.java) - .equalTo("userId", user?.id) - .equalTo("actionType", "voice") - .findAll().count() - - val startTime = 1730408400 + val startTime = 1733011200000 val commVoiceResults = mRealm.where(RealmNews::class.java) .equalTo("userId", user?.id) .greaterThanOrEqualTo("time", startTime) @@ -307,10 +302,16 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N .map { getDateFromTimestamp(it.time) } .distinct() - val courseData = fetchCourseData(mRealm, user?.id) + val courseData = MyProgressFragment.fetchCourseData(mRealm, user?.id) + + val courseId = "4e6b78800b6ad18b4e8b0e1e38a98cac" + val progress = MyProgressFragment.getCourseProgress(courseData, courseId) - val courseId = "9517e3b45a5bb63e69bb8f269216974d" - val progress = getCourseProgress(courseData, courseId) + val hasUnfinishedSurvey = mRealm.where(RealmStepExam::class.java) + .equalTo("courseId", courseId) + .equalTo("type", "surveys") + .findAll() + .any { survey -> !TakeCourseFragment.existsSubmission(mRealm, survey.id, "survey") } val validUrls = listOf( "https://${BuildConfig.PLANET_GUATEMALA_URL}", @@ -323,7 +324,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N val today = LocalDate.now() if (user?.id?.startsWith("guest") == false) { - val endDate = LocalDate.of(today.year, 12, 1) + val endDate = LocalDate.of(today.year, 12, 31) if (today.isBefore(endDate)) { if (settings.getString("serverURL", "") in validUrls) { val course = mRealm.where(RealmMyCourse::class.java) @@ -339,20 +340,21 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } else { "Ingresa al curso $courseName completalo ($current de $max hecho)" } - challengeDialog(uniqueDates.size, courseStatus, allUniqueDates.size) + challengeDialog(uniqueDates.size, courseStatus, allUniqueDates.size, hasUnfinishedSurvey) } else { - challengeDialog(uniqueDates.size, "$courseName no iniciado", allUniqueDates.size) + challengeDialog(uniqueDates.size, "$courseName no iniciado", allUniqueDates.size, hasUnfinishedSurvey) } } } } } - fun challengeDialog(voiceCount: Int, courseStatus: String, allVoiceCount: Int) { + fun challengeDialog (voiceCount: Int, courseStatus: String, allVoiceCount: Int, hasUnfinishedSurvey: Boolean) { val voiceTaskDone = if (voiceCount >= 5) "✅" else "[ ]" val prereqsMet = courseStatus.contains("terminado", ignoreCase = true) && voiceCount >= 5 + var hasValidSync = false val syncTaskDone = if (prereqsMet) { - val hasValidSync = mRealm.where(RealmUserChallengeActions::class.java) + hasValidSync = mRealm.where(RealmUserChallengeActions::class.java) .equalTo("userId", user?.id) .equalTo("actionType", "sync") .count() > 0 @@ -370,30 +372,44 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N if (isCompleted && !hasShownCongrats) { editor.putBoolean("has_shown_congrats", true).apply() val markdownContent = """ - Ganancias totales: **$${calculateProgress(allVoiceCount)}** + Ingresos totales de la comunidad: **$${calculateCommunityProgress(allVoiceCount, hasUnfinishedSurvey)}** /$500 + + Tus ganancias totales: **$${calculateIndividualProgress(voiceCount, hasUnfinishedSurvey)}** /$11 ### ¡Felicidades! Reto Completado
""".trimIndent() - MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount) - .show(supportFragmentManager, "markdown_dialog") + MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount, hasUnfinishedSurvey).show(supportFragmentManager, "markdown_dialog") } else { - val voicesText = if (voiceCount > 0) { - "$voiceCount de 5 Voces diarias" + val cappedVoiceCount = minOf(voiceCount, 5) + val voicesText = if (cappedVoiceCount > 0) { + "$cappedVoiceCount de 5 Voces diarias" } else { "" } val markdownContent = """ - Ganancias totales: **$${calculateProgress(allVoiceCount)}** - ### $courseTaskDone
- ### $voiceTaskDone Comparte tu opinión en Nuestras Voces. $voicesText
+ Ingresos totales de la comunidad: **$${calculateCommunityProgress(allVoiceCount, hasUnfinishedSurvey)}** /$500 + + Tus ganancias totales: **$${calculateIndividualProgress(voiceCount, hasUnfinishedSurvey)}** /$11 + ### $courseTaskDone $1 por encuesta
+ ### $voiceTaskDone Comparte tu opinión en Nuestras Voces.[$2/voz] $voicesText
### $syncTaskDone Recuerda sincronizar la aplicación móvil.
""".trimIndent() - MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount) + MarkdownDialog.newInstance(markdownContent, courseStatus, voiceCount, allVoiceCount, hasUnfinishedSurvey) .show(supportFragmentManager, "markdown_dialog") } } - private fun calculateProgress(allVoiceCount: Int): Int { - return (allVoiceCount) * 5 + private fun calculateIndividualProgress(voiceCount: Int, hasUnfinishedSurvey: Boolean): Int { + val earnedDollarsVoice = minOf(voiceCount, 5) * 2 + val earnedDollarsSurvey = if (!hasUnfinishedSurvey) 1 else 0 + val total = earnedDollarsVoice + earnedDollarsSurvey + return total.coerceAtMost(500) + } + + private fun calculateCommunityProgress (allVoiceCount: Int, hasUnfinishedSurvey: Boolean): Int { + val earnedDollarsVoice = minOf(allVoiceCount, 5) * 2 + val earnedDollarsSurvey = if (!hasUnfinishedSurvey) 1 else 0 + val total = earnedDollarsVoice + earnedDollarsSurvey + return total.coerceAtMost(11) } private fun setupRealmListeners() { @@ -475,7 +491,7 @@ class DashboardActivity : DashboardElementActivity(), OnHomeItemClickListener, N } private fun updateResourceNotification() { - val resourceCount = getLibraryList(mRealm, user?.id).size + val resourceCount = BaseResourceFragment.getLibraryList(mRealm, user?.id).size if (resourceCount > 0) { val existingNotification = mRealm.where(RealmNotification::class.java) .equalTo("userId", user?.id) diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/enterprises/ReportsFragment.kt b/app/src/main/java/org/ole/planet/myplanet/ui/enterprises/ReportsFragment.kt index 5d2026f437..f072e53c62 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/enterprises/ReportsFragment.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/enterprises/ReportsFragment.kt @@ -8,6 +8,8 @@ import android.text.TextUtils import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.LinearLayoutManager import com.google.gson.JsonObject @@ -24,7 +26,6 @@ import org.ole.planet.myplanet.ui.team.BaseTeamFragment import org.ole.planet.myplanet.utilities.SharedPrefManager import org.ole.planet.myplanet.utilities.Utilities import java.io.IOException -import java.io.OutputStream import java.text.SimpleDateFormat import java.util.Calendar import java.util.Date @@ -37,6 +38,7 @@ class ReportsFragment : BaseTeamFragment() { private var startTimeStamp: String? = null private var endTimeStamp: String? = null lateinit var teamType: String + private lateinit var createFileLauncher: ActivityResultLauncher override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { fragmentReportsBinding = FragmentReportsBinding.inflate(inflater, container, false) @@ -158,7 +160,7 @@ class ReportsFragment : BaseTeamFragment() { type = "text/csv" putExtra(Intent.EXTRA_TITLE, "Report_of_${teamName}_Financial_Report_Summary_on_${formattedDate}") } - startActivityForResult(intent, CREATE_FILE_REQUEST_CODE) + createFileLauncher.launch(intent) } list = mRealm.where(RealmMyTeam::class.java).equalTo("teamId", teamId) @@ -169,6 +171,39 @@ class ReportsFragment : BaseTeamFragment() { updatedReportsList(results) } + createFileLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val uri = result.data?.data + if (uri != null) { + try { + val reports = mRealm.where(RealmMyTeam::class.java).equalTo("teamId", teamId) + .equalTo("docType", "report") + .sort("date", Sort.DESCENDING).findAll() + val csvBuilder = StringBuilder() + csvBuilder.append("${prefData.getTeamName()} Financial Report Summary\n\n") + csvBuilder.append("Start Date, End Date, Created Date, Updated Date, Beginning Balance, Sales, Other Income, Wages, Other Expenses, Profit/Loss, Ending Balance\n") + for (report in reports) { + val dateFormat = SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (z)", Locale.US) + val totalIncome = report.sales + report.otherIncome + val totalExpenses = report.wages + report.otherExpenses + val profitLoss = totalIncome - totalExpenses + val endingBalance = profitLoss + report.beginningBalance + csvBuilder.append("${dateFormat.format(report.startDate)}, ${dateFormat.format(report.endDate)}, ${dateFormat.format(report.createdDate)}, ${dateFormat.format(report.updatedDate)}, ${report.beginningBalance}, ${report.sales}, ${report.otherIncome}, ${report.wages}, ${report.otherExpenses}, $profitLoss, $endingBalance\n") + } + + requireContext().contentResolver.openOutputStream(uri)?.use { outputStream -> + outputStream.write("$csvBuilder".toByteArray()) + } + Utilities.toast(requireContext(), getString(R.string.csv_file_saved_successfully)) + } catch (e: IOException) { + e.printStackTrace() + Utilities.toast(requireContext(), getString(R.string.failed_to_save_csv_file)) + } + } else { + Utilities.toast(requireContext(), getString(R.string.export_cancelled)) + } + } + } return fragmentReportsBinding.root } @@ -181,6 +216,7 @@ class ReportsFragment : BaseTeamFragment() { } override fun onNewsItemClick(news: RealmNews?) {} + override fun clearImages() { imageList.clear() llImage?.removeAllViews() @@ -195,43 +231,4 @@ class ReportsFragment : BaseTeamFragment() { adapterReports.notifyDataSetChanged() } } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == CREATE_FILE_REQUEST_CODE) { - if (resultCode == Activity.RESULT_CANCELED) { - Utilities.toast(requireContext(), "export cancelled.") - } else if (resultCode == Activity.RESULT_OK) { - data?.data?.also { uri -> - try { - val reports = mRealm.where(RealmMyTeam::class.java).equalTo("teamId", teamId) - .equalTo("docType", "report") - .sort("date", Sort.DESCENDING).findAll() - val csvBuilder = StringBuilder() - csvBuilder.append("${prefData.getTeamName()} Financial Report Summary\n\n") - csvBuilder.append("Start Date, End Date, Created Date, Updated Date, Beginning Balance, Sales, Other Income, Wages, Other Expenses, Profit/Loss, Ending Balance\n") - for (report in reports) { - val dateFormat = SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (z)", Locale.US) - val totalIncome = report.sales + report.otherIncome - val totalExpenses = report.wages + report.otherExpenses - val profitLoss = totalIncome - totalExpenses - val endingBalance = profitLoss + report.beginningBalance - csvBuilder.append("${dateFormat.format(report.startDate)}, ${dateFormat.format(report.endDate)}, ${dateFormat.format(report.createdDate)}, ${dateFormat.format(report.updatedDate)}, ${report.beginningBalance}, ${report.sales}, ${report.otherIncome}, ${report.wages}, ${report.otherExpenses}, $profitLoss, $endingBalance\n") - } - - val outputStream: OutputStream? = requireContext().contentResolver.openOutputStream(uri) - outputStream?.write(csvBuilder.toString().toByteArray()) - outputStream?.close() - Utilities.toast(requireContext(), "CSV file saved successfully.") - } catch (e: IOException) { - Utilities.toast(requireContext(), "Failed to save CSV file.") - } - } - } - } - } - - companion object { - private const val CREATE_FILE_REQUEST_CODE = 1 - } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/exam/TakeExamFragment.kt b/app/src/main/java/org/ole/planet/myplanet/ui/exam/TakeExamFragment.kt index 20bb49b0a6..af0183729a 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/exam/TakeExamFragment.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/exam/TakeExamFragment.kt @@ -189,7 +189,7 @@ class TakeExamFragment : BaseExamFragment(), View.OnClickListener, CompoundButto if (isRadio) { fragmentTakeExamBinding.groupChoices.addView(rdBtn) } else { - rdBtn.setTextColor(resources.getColor(R.color.daynight_textColor)) + rdBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.daynight_textColor)) rdBtn.buttonTintList = ContextCompat.getColorStateList(requireContext(), R.color.daynight_textColor) fragmentTakeExamBinding.llCheckbox.addView(rdBtn) } diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/mylife/AdapterMyLife.kt b/app/src/main/java/org/ole/planet/myplanet/ui/mylife/AdapterMyLife.kt index 39234cecff..b47c19adb6 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/mylife/AdapterMyLife.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/mylife/AdapterMyLife.kt @@ -13,6 +13,7 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.recyclerview.widget.RecyclerView import io.realm.Realm @@ -81,10 +82,10 @@ class AdapterMyLife(private val context: Context, private val myLifeList: List diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/team/teamMember/AdapterJoinedMember.kt b/app/src/main/java/org/ole/planet/myplanet/ui/team/teamMember/AdapterJoinedMember.kt index 1c83174100..3fec35d920 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/team/teamMember/AdapterJoinedMember.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/team/teamMember/AdapterJoinedMember.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.TextView +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat @@ -18,6 +19,7 @@ import org.ole.planet.myplanet.model.RealmTeamLog import org.ole.planet.myplanet.model.RealmUserModel import org.ole.planet.myplanet.service.UserProfileDbHandler import io.realm.Realm +import io.realm.Sort import org.ole.planet.myplanet.utilities.Utilities class AdapterJoinedMember(private val context: Context, private val list: List, private val mRealm: Realm, private val teamId: String) : RecyclerView.Adapter() { @@ -77,11 +79,15 @@ class AdapterJoinedMember(private val context: Context, private val list: List, isLoggedInUserTeamLeader: Boolean ) { - if (isLoggedInUserTeamLeader) { + if (isLoggedInUserTeamLeader && list.size>1) { rowJoinedUserBinding.icMore.visibility = View.VISIBLE rowJoinedUserBinding.icMore.setOnClickListener { val builder = AlertDialog.Builder(context, R.style.AlertDialogTheme) - val adapter = object : ArrayAdapter(context, android.R.layout.simple_list_item_1, overflowMenuOptions) { + val adapter = object : ArrayAdapter( + context, + android.R.layout.simple_list_item_1, + overflowMenuOptions + ) { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val view = super.getView(position, convertView, parent) as TextView val color = ContextCompat.getColor(context, R.color.daynight_textColor) @@ -90,10 +96,31 @@ class AdapterJoinedMember(private val context: Context, private val list: List - if (i == 0) { - reject(list[position], position) + if (position >= 0 && position < list.size) { + when (i) { + 0 -> { + if (currentUser.id != list[position].id) { + reject(list[position], position) + } else { + val nextOfKin= getNextOfKin() + if(nextOfKin!=null){ + makeLeader(nextOfKin) + reject(list[position], position) + } + else { + Toast.makeText(context, R.string.cannot_remove_user, Toast.LENGTH_SHORT).show() + } + } + } + 1 -> { + makeLeader(list[position]) + } + else -> { + Toast.makeText(context, R.string.cannot_remove_user, Toast.LENGTH_SHORT).show() + } + } } else { - makeLeader(list[position]) + Toast.makeText(context, R.string.cannot_remove_user, Toast.LENGTH_SHORT).show() } }.setNegativeButton(R.string.dismiss, null).show() } @@ -102,7 +129,29 @@ class AdapterJoinedMember(private val context: Context, private val list: List = mRealm.where(RealmMyTeam::class.java) + .equalTo("teamId", teamId) + .equalTo("isLeader", false) + .notEqualTo("status","archived") + .sort("createdDate", Sort.DESCENDING) + .findAll() + val successor = if (members.isNotEmpty()) members?.first() else null + if(successor==null){ + return null + } + else{ + val user= mRealm.where(RealmUserModel::class.java).equalTo("id", successor.userId).findFirst() + return user + } + return null + } + private fun makeLeader(userModel: RealmUserModel) { + if(userModel==null){ + Utilities.toast(context, context.getString(R.string.cannot_remove_user)) + return + } mRealm.executeTransaction { realm -> val team = realm.where(RealmMyTeam::class.java) .equalTo("teamId", teamId) @@ -114,6 +163,7 @@ class AdapterJoinedMember(private val context: Context, private val list: List = getJoinedMember(teamId, mRealm) val filteredUserList = userList.filter { user -> user.getFullName().isNotBlank() } + if (filteredUserList.isEmpty()) { + Toast.makeText(context, R.string.no_members_task, Toast.LENGTH_SHORT).show() + return + } val adapter: ArrayAdapter = UserListArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, filteredUserList) alertUsersSpinnerBinding.spnUser.adapter = adapter AlertDialog.Builder(requireActivity(), R.style.AlertDialogTheme) .setTitle(R.string.select_member) .setView(alertUsersSpinnerBinding.root).setCancelable(false) .setPositiveButton(R.string.ok) { _: DialogInterface?, _: Int -> - val user = alertUsersSpinnerBinding.spnUser.selectedItem as RealmUserModel + val selectedItem = alertUsersSpinnerBinding.spnUser.selectedItem + if (selectedItem == null) { + Toast.makeText(context, R.string.no_member_selected, Toast.LENGTH_SHORT).show() + return@setPositiveButton + } + val user = selectedItem as RealmUserModel val userId = user.id if (!mRealm.isInTransaction) { mRealm.beginTransaction() diff --git a/app/src/main/java/org/ole/planet/myplanet/utilities/MarkdownDialog.kt b/app/src/main/java/org/ole/planet/myplanet/utilities/MarkdownDialog.kt index 8da283fb40..c6c2804866 100644 --- a/app/src/main/java/org/ole/planet/myplanet/utilities/MarkdownDialog.kt +++ b/app/src/main/java/org/ole/planet/myplanet/utilities/MarkdownDialog.kt @@ -28,20 +28,23 @@ class MarkdownDialog : DialogFragment() { private var courseStatus: String = "" private var voiceCount: Int = 0 private var allVoiceCount: Int = 0 + private var hasUnfinishedSurvey: Boolean = false companion object { private const val ARG_MARKDOWN_CONTENT = "markdown_content" private const val ARG_COURSE_STATUS = "course_status" private const val ARG_VOICE_COUNT = "voice_count" private const val ARG_ALL_VOICE_COUNT = "all_voice_count" + private const val ARG_HAS_UNFINISHED_SURVEY = "has_unfinished_survey" - fun newInstance(markdownContent: String, courseStatus: String, voiceCount: Int, allVoiceCount: Int): MarkdownDialog { + fun newInstance(markdownContent: String, courseStatus: String, voiceCount: Int, allVoiceCount: Int, hasUnfinishedSurvey: Boolean): MarkdownDialog { val fragment = MarkdownDialog() val args = Bundle().apply { putString(ARG_MARKDOWN_CONTENT, markdownContent) putString(ARG_COURSE_STATUS, courseStatus) putInt(ARG_VOICE_COUNT, voiceCount) putInt(ARG_ALL_VOICE_COUNT, allVoiceCount) + putBoolean(ARG_HAS_UNFINISHED_SURVEY, hasUnfinishedSurvey) } fragment.arguments = args return fragment @@ -54,6 +57,7 @@ class MarkdownDialog : DialogFragment() { courseStatus = arguments?.getString(ARG_COURSE_STATUS) ?: "" voiceCount = arguments?.getInt(ARG_VOICE_COUNT, 0) ?: 0 allVoiceCount = arguments?.getInt(ARG_ALL_VOICE_COUNT, 0) ?: 0 + hasUnfinishedSurvey = arguments?.getBoolean(ARG_HAS_UNFINISHED_SURVEY, false) == true } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -80,10 +84,11 @@ class MarkdownDialog : DialogFragment() { } setupCloseButton() - val earnedDollars = allVoiceCount * 5 - val progressValue = ((earnedDollars.toDouble() / 500) * 100).toInt() + val earnedDollarsVoice = allVoiceCount * 2 + val earnedDollarsSurvey = if (!hasUnfinishedSurvey) 1 else 0 + val total = earnedDollarsVoice + earnedDollarsSurvey + val progressValue = ((total.toDouble() / 500) * 100).toInt().coerceAtMost(100) dialogCampaignChallengeBinding.progressBar.progress = progressValue - } override fun onStart() { @@ -102,8 +107,7 @@ class MarkdownDialog : DialogFragment() { val isCompleted = courseStatus.contains("terminado") && voiceCount >= 5 && (activity as? DashboardActivity)?.mRealm?.let { realm -> realm.where(RealmUserChallengeActions::class.java) .equalTo("userId", (activity as? DashboardActivity)?.user?.id) - .equalTo("actionType", "sync") - .count() > 0 + .equalTo("actionType", "sync").count() > 0 } == true visibility = if (isCompleted) View.GONE else View.VISIBLE @@ -117,7 +121,7 @@ class MarkdownDialog : DialogFragment() { text = buttonText setOnClickListener { - val courseId = "9517e3b45a5bb63e69bb8f269216974d" + val courseId = "4e6b78800b6ad18b4e8b0e1e38a98cac" when (buttonText) { context.getString(R.string.start), context.getString(R.string.continuation) -> { val fragment = TakeCourseFragment().apply { diff --git a/app/src/main/res/drawable/december_challenge.jpeg b/app/src/main/res/drawable/december_challenge.jpeg new file mode 100644 index 0000000000..944b8beae6 Binary files /dev/null and b/app/src/main/res/drawable/december_challenge.jpeg differ diff --git a/app/src/main/res/drawable/november_challenge.jpeg b/app/src/main/res/drawable/november_challenge.jpeg deleted file mode 100644 index 885e65f056..0000000000 Binary files a/app/src/main/res/drawable/november_challenge.jpeg and /dev/null differ diff --git a/app/src/main/res/layout/dialog_campaign_challenge.xml b/app/src/main/res/layout/dialog_campaign_challenge.xml index 30acef1db3..1ace47da7c 100644 --- a/app/src/main/res/layout/dialog_campaign_challenge.xml +++ b/app/src/main/res/layout/dialog_campaign_challenge.xml @@ -21,7 +21,7 @@ android:layout_height="150dp" android:contentDescription="markdown image" android:scaleType="fitCenter" - android:src="@drawable/november_challenge" + android:src="@drawable/december_challenge" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/closeButton" /> diff --git a/app/src/main/res/layout/fragment_team_detail.xml b/app/src/main/res/layout/fragment_team_detail.xml index 99ad60c3c2..8938f536a7 100644 --- a/app/src/main/res/layout/fragment_team_detail.xml +++ b/app/src/main/res/layout/fragment_team_detail.xml @@ -63,7 +63,7 @@