Skip to content
This repository was archived by the owner on Oct 12, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/assets/swirling_oracle.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion app/src/main/java/org/hackillinois/android/API.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.hackillinois.android

import RedeemCart
import okhttp3.ResponseBody
import org.hackillinois.android.database.entity.*
import org.hackillinois.android.model.event.EventsList
Expand Down Expand Up @@ -84,7 +85,7 @@ interface API {
suspend fun removeItemCart(@Path("itemId") itemId: String): Response<ResponseBody>

@POST("shop/cart/redeem/")
suspend fun redeemCart(@Body body: QRCode): Cart
suspend fun redeemCart(@Body body: QRCode): RedeemCart

// STAFF

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data class RedeemCart(
val items: List<CartItem>
)

data class CartItem(
val itemId: String,
val name: String,
val quantity: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,37 @@ import org.hackillinois.android.view.onboarding.OnboardingPageFragment
class OnboardingActivity : FragmentActivity() {

private val images = listOf(
R.drawable.login_logo_2024,
R.drawable.countdown_2024,
R.drawable.schedule_2024,
R.drawable.scanner_2024,
R.drawable.point_shop_2024,
R.drawable.profile_2024,
R.drawable.transparent_image,
R.drawable.onboarding_1,
R.drawable.onboarding_2,
R.drawable.onboarding_3,
R.drawable.onboarding_4,
R.drawable.onboarding_5,
R.drawable.onboarding_6,
R.drawable.onboarding_7
)

private val titles = listOf(
R.string.onboarding_welcome_title,
R.string.onboarding_countdown_title,
R.string.onboarding_schedule_title,
R.string.onboarding_scan_title,
R.string.onboarding_check_in_title,
R.string.onboarding_shop_title,
R.string.onboarding_profile_title,
R.string.onboarding_cart_title,
R.string.onboarding_scan_title,
R.string.onboarding_profile_title

)

private val descriptions = listOf(
R.string.onboarding_welcome_description,
R.string.onboarding_countdown_description,
R.string.onboarding_schedule_description,
R.string.onboarding_scan_description,
R.string.onboarding_check_in_description,
R.string.onboarding_shop_description,
R.string.onboarding_profile_description,
R.string.onboarding_cart_description,
R.string.onboarding_scan_description,
R.string.onboarding_profile_description
)

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -47,6 +54,7 @@ class OnboardingActivity : FragmentActivity() {

view_pager.adapter = ScreenSlidePagerAdapter(this)
view_pager.offscreenPageLimit = 1
// view_pager.adapter = OnboardingAdapter(images)

// connect toggled circle buttons to the view pager
TabLayoutMediator(tab_layout, view_pager) { tab, position ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ class ScannerFragment : Fragment(), SimpleScanDialogFragment.OnSimpleOKButtonSel
val eventId = getChipEventId()
viewModel.checkInAttendee(UserEventPair(eventId, userToken))
}
"point-shop" -> {
Log.d("Shop Raw Text: ", "" + it.text)
val QRCode: String = it.text
Log.d("Point Text: ", QRCode)
viewModel.redeemAttendeeCart(QRCode(QRCode))
}
else -> {
displayToast(R.string.something_went_wrong_message)
closeScannerPage()
Expand All @@ -153,12 +159,6 @@ class ScannerFragment : Fragment(), SimpleScanDialogFragment.OnSimpleOKButtonSel
Log.d("Mentor Text: ", "" + mentorId)
viewModel.checkInMentor(MentorId(mentorId))
}
"point-shop" -> {
Log.d("Shop Raw Text: ", "" + it.text)
val QRCode: String = it.text
Log.d("Point Text: ", QRCode)
viewModel.redeemAttendeeCart(QRCode(QRCode))
}
else -> {
displayToast(R.string.something_went_wrong_message)
closeScannerPage()
Expand Down Expand Up @@ -347,13 +347,22 @@ class ScannerFragment : Fragment(), SimpleScanDialogFragment.OnSimpleOKButtonSel

private fun closeScannerPage() {
// set bottom app bar visible again and pop scanner fragment from the backstack
val appBar = activity?.findViewById<BottomAppBar>(R.id.bottomAppBar)
val scannerBtn = activity?.findViewById<FloatingActionButton>(R.id.code_entry_fab)
if (appBar != null && scannerBtn != null) {
appBar.visibility = View.VISIBLE
scannerBtn.visibility = View.VISIBLE
// val appBar = activity?.findViewById<BottomAppBar>(R.id.bottomAppBar)
// val scannerBtn = activity?.findViewById<FloatingActionButton>(R.id.code_entry_fab)
// if (appBar != null && scannerBtn != null) {
// appBar.visibility = View.VISIBLE
// scannerBtn.visibility = View.VISIBLE
// }
// activity?.supportFragmentManager?.popBackStackImmediate()
activity?.runOnUiThread {
val appBar = activity?.findViewById<BottomAppBar>(R.id.bottomAppBar)
val scannerBtn = activity?.findViewById<FloatingActionButton>(R.id.code_entry_fab)
if (appBar != null && scannerBtn != null) {
appBar.visibility = View.VISIBLE
scannerBtn.visibility = View.VISIBLE
}
activity?.supportFragmentManager?.popBackStackImmediate()
}
activity?.supportFragmentManager?.popBackStackImmediate()
}

override fun continueScanningAfterSimpleDialog() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.hackillinois.android.view.scanner

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand Down Expand Up @@ -47,6 +48,7 @@ class StaffScannerFragment : Fragment() {
appBar.visibility = View.INVISIBLE
scannerBtn.visibility = View.INVISIBLE
}
Log.d("Staff Scanner Fragment: ", "Attempting to open scanner fragment")
val scannerFragment = ScannerFragment.newInstance("point-shop")
(context as MainActivity).switchFragment(scannerFragment, true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import org.hackillinois.android.App
import org.hackillinois.android.R
import org.hackillinois.android.database.entity.Cart
import org.hackillinois.android.database.entity.ShopItem
import org.hackillinois.android.view.scanner.SimpleScanDialogFragment
import org.json.JSONObject

class CartFragment : Fragment(), CartAdapter.OnQuantityChangeListener {

Expand Down Expand Up @@ -85,10 +87,24 @@ class CartFragment : Fragment(), CartAdapter.OnQuantityChangeListener {
Log.d("CartDebug", "Item added: ${response.body()}")
fetchCartData() // Refresh cart
} else {
Log.e("CartDebug", "Failed to add item: ${response.code()}")
// Extract error message from response.errorBody()
val errorMessage = try {
val errorBody = response.errorBody()?.string()
if (!errorBody.isNullOrEmpty()) {
val jsonObject = JSONObject(errorBody)
jsonObject.optString("message", "Failed to add item: ${response.code()}")
} else {
"Failed to add item: ${response.code()}"
}
} catch (e: Exception) {
"Failed to add item: ${response.code()}"
}
Log.e("CartDebug", "Failed to add item: $errorMessage")
showErrorDialog("Error", errorMessage)
}
} catch (e: Exception) {
Log.e("CartDebug", "Error adding item to cart", e)
showErrorDialog("Error", "Failed to add item: ${e.message}")
}
}
}
Expand Down Expand Up @@ -117,4 +133,19 @@ class CartFragment : Fragment(), CartAdapter.OnQuantityChangeListener {
}
}
}

private fun showErrorDialog(title: String, message: String) {
val args = Bundle().apply {
putString("KEY_TITLE", title)
putString("KEY_SUBTITLE", message)
}
val dialog = SimpleScanDialogFragment()
dialog.arguments = args
dialog.setSimpleOKButtonListener(object : SimpleScanDialogFragment.OnSimpleOKButtonSelected {
override fun continueScanningAfterSimpleDialog() {
// Optionally perform an action here (e.g. refresh the cart), or leave empty.
}
})
dialog.show(requireActivity().supportFragmentManager, "CartErrorDialogFragment")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import org.hackillinois.android.R
import org.hackillinois.android.common.JWTUtilities
import org.hackillinois.android.database.entity.Profile
import org.hackillinois.android.database.entity.ShopItem
import org.hackillinois.android.view.scanner.SimpleScanDialogFragment
import org.hackillinois.android.viewmodel.ShopViewModel
import org.json.JSONObject

class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener {

Expand Down Expand Up @@ -285,7 +287,7 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener {

private fun updateCoinTotalUI(newProfile: Profile?) {
if (newProfile != null) {
coin_total_textview.text = String.format("%,d", newProfile.pointsAccumulated)
number_of_coins_textview.text = String.format("%,d", newProfile.pointsAccumulated)
}
}

Expand All @@ -307,16 +309,27 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener {
try {
val response = App.getAPI().addItemCart(item.itemId)
if (response.isSuccessful) {
// Update UI or local data with the new cart state
Log.d("CartDebug", "Item added: ${response.body()}")
Toast.makeText(requireContext(), "${item.name} redeemed successfully!", Toast.LENGTH_SHORT).show()
} else {
Log.e("CartDebug", "Failed to add item: ${response.code()}")
Toast.makeText(requireContext(), "Failed to add item: ${response.code()}", Toast.LENGTH_SHORT).show()
val errorMessage: String = try {
val errorBody = response.errorBody()?.string()
if (!errorBody.isNullOrEmpty()) {
// Assuming your error JSON contains a "message" field
val jsonObject = JSONObject(errorBody)
jsonObject.optString("message", "Failed to add item: ${response.code()}")
} else {
"Failed to add item: ${response.code()}"
}
} catch (e: Exception) {
"Failed to add item: ${response.code()}"
}
Log.e("CartDebug", "Failed to add item: $errorMessage")
showSimpleDialogFragment("Error", errorMessage)
}
} catch (e: Exception) {
Log.e("CartDebug", "Error adding item to cart", e)
Toast.makeText(requireContext(), "Failed to add item: ${e.message}", Toast.LENGTH_SHORT).show()
showSimpleDialogFragment("Error", "Failed to add item: ${e.message}")
}
updateShopUI()
}
Expand All @@ -337,4 +350,21 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener {
onBuyItem(secondItem)
}
}

private fun showSimpleDialogFragment(title: String, subtitle: String) {
val args = Bundle().apply {
putString("KEY_TITLE", title)
putString("KEY_SUBTITLE", subtitle)
}
// Reuse your SimpleScanDialogFragment if it fits your needs;
// otherwise, you can create a similar ShopErrorDialogFragment.
val dialog = SimpleScanDialogFragment()
dialog.arguments = args
dialog.setSimpleOKButtonListener(object : SimpleScanDialogFragment.OnSimpleOKButtonSelected {
override fun continueScanningAfterSimpleDialog() {
// Optionally perform an action after dismissal (or leave empty)
}
})
dialog.show(requireActivity().supportFragmentManager, "SimpleScanDialogFragment")
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.hackillinois.android.viewmodel

import RedeemCart
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
Expand Down Expand Up @@ -57,21 +58,27 @@ class ScannerViewModel : ViewModel() {
fun redeemAttendeeCart(body: QRCode) {
viewModelScope.launch {
try {
App.getAPI().redeemCart(body)
val message = "Attendee successfully redeemed cart at Point Shop."
val scanStatus = ScanStatus(message, true)
lastScanStatus.postValue(scanStatus)
val response: RedeemCart = App.getAPI().redeemCart(body)
val items = response.items

val redeemedMessage = if (items.isEmpty()) {
"No items redeemed."
} else {
items.filter { it.quantity > 0 }
.joinToString(separator = ", ") { "${it.name}: ${it.quantity}" }
}
val message = "Redeemed items: $redeemedMessage"
lastScanStatus.postValue(ScanStatus(message, true))
} catch (e: Exception) {
var error = e.message.toString()
try {
if (e is HttpException) {
val jsonObject = JSONObject("" + e.response()?.errorBody()?.string())
val jsonObject = JSONObject(e.response()?.errorBody()?.string() ?: "")
error = jsonObject.optString("message", e.message.toString())
}
} catch (e: Exception) { }
} catch (ex: Exception) { }
Log.e("Failed to redeem cart", error)
val scanStatus = ScanStatus("Scan failed: $error", false)
lastScanStatus.postValue(scanStatus)
lastScanStatus.postValue(ScanStatus("Scan failed: $error", false))
}
}
}
Expand Down Expand Up @@ -149,7 +156,7 @@ class ScannerViewModel : ViewModel() {
try {
Log.d("ITEMINSTANCE", body.toString())
val item = App.getAPI().buyShopItem(body)
val message = "You have successfully redeemed ${item.name} from the Point Shop!"
val message = "You have successfully added ${item.name} to your cart!"
val scanStatus = ScanStatus(message, true)
lastScanStatus.postValue(scanStatus)
} catch (e: Exception) {
Expand Down
Binary file added app/src/main/res/drawable/login_logo_2025.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable/onboarding_bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/src/main/res/drawable/rounded_cream_bg.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#80F5F0DD" />
<corners android:radius="30dp"/>
</shape>
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/tab_indicator_default.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
android:thicknessRatio="9"
android:useLevel="false">

<solid android:color="#FFFFFF"/>
<solid android:color="@color/black"/>

</shape>
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/tab_indicator_selected.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
android:shape="ring"
android:thicknessRatio="4.5"
android:useLevel="false" >
<solid android:color="#FFFFFF" />
<solid android:color="@color/black" />
</shape>
3 changes: 3 additions & 0 deletions app/src/main/res/drawable/transparent_image.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent"/>
</shape>
Loading