From bd6e814c3f2c9ca11289e1ff03ac64024994a3f5 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Sun, 26 Jan 2025 13:19:00 -0600 Subject: [PATCH 01/20] intial point shop changes --- .../android/view/shop/ShopFragment.kt | 16 +- .../res/drawable/point_shop_cloud_side.xml | 55 ++++++ .../res/drawable/point_shop_cloud_top.xml | 55 ++++++ .../drawable/point_shop_coin_background.xml | 9 + .../main/res/drawable/point_shop_counter.xml | 157 +++++++++++++++ .../drawable/point_shop_counter_bottom.png | Bin 0 -> 2568 bytes .../drawable/point_shop_counter_middle.png | Bin 0 -> 2300 bytes .../main/res/drawable/point_shop_currency.xml | 128 ++++++++++++ app/src/main/res/drawable/point_shop_girl.xml | 183 ++++++++++++++++++ .../point_shop_gradient_background.xml | 12 ++ .../point_shop_selected_background.png | Bin 0 -> 878 bytes .../point_shop_unselected_background.png | Bin 0 -> 957 bytes .../main/res/layout/fragment_point_shop.xml | 156 ++++++++++----- app/src/main/res/values/colors.xml | 3 + 14 files changed, 714 insertions(+), 60 deletions(-) create mode 100644 app/src/main/res/drawable/point_shop_cloud_side.xml create mode 100644 app/src/main/res/drawable/point_shop_cloud_top.xml create mode 100644 app/src/main/res/drawable/point_shop_coin_background.xml create mode 100644 app/src/main/res/drawable/point_shop_counter.xml create mode 100644 app/src/main/res/drawable/point_shop_counter_bottom.png create mode 100644 app/src/main/res/drawable/point_shop_counter_middle.png create mode 100644 app/src/main/res/drawable/point_shop_currency.xml create mode 100644 app/src/main/res/drawable/point_shop_girl.xml create mode 100644 app/src/main/res/drawable/point_shop_gradient_background.xml create mode 100644 app/src/main/res/drawable/point_shop_selected_background.png create mode 100644 app/src/main/res/drawable/point_shop_unselected_background.png diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index fe0e1f2e..065fc596 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -13,7 +13,7 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.synthetic.main.fragment_point_shop.coin_total_textview +import kotlinx.android.synthetic.main.fragment_point_shop.number_of_coins_textview import kotlinx.android.synthetic.main.fragment_point_shop.view.recyclerview_point_shop import org.hackillinois.android.R import org.hackillinois.android.common.JWTUtilities @@ -92,8 +92,8 @@ class ShopFragment : Fragment() { if (hasLoggedIn() && isAttendee()) { // set coin views visible for attendee - val coinBg: TextView = view.findViewById(R.id.total_coin_view) - val coinText: TextView = view.findViewById(R.id.coin_total_textview) + val coinBg: TextView = view.findViewById(R.id.number_of_coins_background) + val coinText: TextView = view.findViewById(R.id.number_of_coins_textview) val coinImg: ImageView = view.findViewById(R.id.coin_imageview) coinBg.visibility = View.VISIBLE coinText.visibility = View.VISIBLE @@ -130,9 +130,9 @@ class ShopFragment : Fragment() { private val merchClickListener = View.OnClickListener { if (!merchButton.isSelected) { merchButton.isSelected = true - merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_selected_tab) } + merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_selected_background) } raffleButton.isSelected = false - raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_unselected_tab) } + raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_unselected_background) } showingMerch = true updateShopUI() } @@ -142,9 +142,9 @@ class ShopFragment : Fragment() { private val raffleClickListener = View.OnClickListener { if (!raffleButton.isSelected) { raffleButton.isSelected = true - raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_selected_tab) } + raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_selected_background) } merchButton.isSelected = false - merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_unselected_tab) } + merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_unselected_background) } showingMerch = false updateShopUI() } @@ -152,7 +152,7 @@ class ShopFragment : Fragment() { private fun updateCoinTotalUI(newProfile: Profile?) { if (newProfile != null) { - coin_total_textview.text = String.format("%,d", newProfile.coins) + number_of_coins_textview.text = String.format("%,d", newProfile.coins) } } diff --git a/app/src/main/res/drawable/point_shop_cloud_side.xml b/app/src/main/res/drawable/point_shop_cloud_side.xml new file mode 100644 index 00000000..9a94573c --- /dev/null +++ b/app/src/main/res/drawable/point_shop_cloud_side.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_cloud_top.xml b/app/src/main/res/drawable/point_shop_cloud_top.xml new file mode 100644 index 00000000..11a2728a --- /dev/null +++ b/app/src/main/res/drawable/point_shop_cloud_top.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_coin_background.xml b/app/src/main/res/drawable/point_shop_coin_background.xml new file mode 100644 index 00000000..2d2ce2e0 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_coin_background.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/point_shop_counter.xml b/app/src/main/res/drawable/point_shop_counter.xml new file mode 100644 index 00000000..04ab76e4 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_counter.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_counter_bottom.png b/app/src/main/res/drawable/point_shop_counter_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..6024296761189fe821d486db5db8f925c6eb6ac4 GIT binary patch literal 2568 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/point_shop_counter_middle.png b/app/src/main/res/drawable/point_shop_counter_middle.png new file mode 100644 index 0000000000000000000000000000000000000000..42a29764eaf98db2e420bc770ac0bb7bc09cebc9 GIT binary patch literal 2300 zcmZuzdpK0<8lOQU*`~G>wp-4up>~InZI8-!zszVt(O}5vJdOJ>#URFrP`jwPg>q>s z+G=tOQOq#qblO8mF%qGgFeGw~VcTofIp=xKe$F3jz2En(_xs-8`}=gYaJaHPE ze%J(q!8F|QF5WO0+#MWW*@yt&5q!No(5Rijlj2}7^{vnYhZPj*fQ#@rZ=4gXvQu9U zPE^7iJse@Mdo1w+<+nV-6M<>rR>T%MRUB zb`+3{=B~AP!!{B_T)GzRhX;y1km};u=9RVK_1Qwpn#P>)F=5Om2kVXx4p9Ma*hsuD zu~#eYl1UiPG=zdWM_G=Cj|;9%<#RmR@S{x1RU#vL_>a#E_U(P^D~a$cjFr2=c{pCv zXZk+9HCNsKaFnE+^-JnnBW!hK<_oZ5m5kXJfOlicP7e!rJ*~a(eNR6J`fyLB@T=w{oakkV>)BlMuKL>GyNKEx}vk1pepwfx1+17K)KOUdw zwt6-!aKsmop6@Cg!09*t-c_+A<@KA;9CBE z_`+SK>f5JoBn}Z$@A)CD2I)5As4;Xo7|yN!c~jgUK|Tm8e~3(ux>*{!qi@ema!q9- z!uIA~JOrWniS^kas}P5bOc3FCV2a~XwMb_1GMWiIuVwWTkeb{T{B>G?s>GNf8FHQ- zy}}0Ff{Kh=ZIMz2p1jEMnD;PJD}T51m#0C$IWKV6yc#AKqk6$)1V}IP+2Mq)E`+Yf zq9K=fqM~u`wOBBk|K3GJxiiq`gg%?9q zA#9P?+iB`Z9AlGd33gEjSjpdfCQS{_ytKAm;)*gUQd}se7*5}Y6eoW|Gt?jrCd_TN zNTa}{QJDTNh{)RAeQ;lnhIr*8q{0kO`D1y=F`>cZ|UN)OJY zeHJFlPL>GHp)M3VTTY^aE+TSvO`>Tvg4#}q9jR-5aBM7=6ag<&&;!9MI!|qp2}G1J z2=OG49GTEduJM5+5Fe*ybc}Q-|DzW7u+i0_Hn_$0R$hL0S#Gi<=H=9N7X8MCnR}&P z9n#v)>63|@KpGC_y@eyRE6%%Iz5nYiC^+xEBP@d;bt$M6$zFVoPF(Dv_K{ znR^s4{GTtR%dSBTiMhJ9#{dgV*Z{a63{r51ozgsr0-j* zG^&x6e0sP&GcNVs>b_66oGkY%%Z1o#&ztFiK|})oJ-MDoeVs}t>-n2@>jl;##~x@S z!P~4`Q}s6`nV1a_%t3Ke`tH)oF6R>m+8$aLKZm@^Y~RjEXynB{JIQ zx$0S9A-uBc=OJyz79QiYwDsIUjx=~0?*xK?FE!a&PL>m>;y#3wlyZsjnH<~gSreh? zPKrKO{6zQuDNGU#sUCM6xxMEjHQ6+9|bBH#jV`{)!-bDK^+D z1fEUjeq&;*Oo48BwR;H<^$u!dN{cM9!}hf8W{KdkX}A5R>RreT)yLcA=sEdfITOPH zQ3AL}Xkqp|cPXAbg#v4!+7YZdMDV9+bStE&X=*)~c46qXz;2(~rm--2s>A{)v3mi6 z-I^7cKCybI|5T&FJm(Wj1$$VyEnFH6kZy8H!6MY4Zz(?!To5XvKxIj>s#5h2n-g(^ zk|k0|J_9=ko3G4sr=T`bo%Jq#i29I2>BcDq?vzwR1sE7N?FlI>I@k7R8yo)5(JjMj z5WJ2{C8!HT#l^71vH?eKC{T5c#a5;czPFgw1gRCTTZ-IfHAN=ZLXt4NCXtL5CXT1p*k#gIg9_ z)@9$cM(t=~rz8aVgK$)hC(w5%5~jYG1BnEM+X2w+;=8!Ph6cxGs5{KCfv)Futba44 zXZD&v&H|f++jOrIwQ>Bx!a0$Q2wrX}*u}8f!=j{Ng6HVzXNuq3<%)6>oW~4*T6%1aH;#5NA1j5>SE=eii^@M z`U|DE<2y#|$~vvExX~OYv~KFh>|5>{pcw_fSyvXHtBk}u + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_girl.xml b/app/src/main/res/drawable/point_shop_girl.xml new file mode 100644 index 00000000..04cf2034 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_girl.xml @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_gradient_background.xml b/app/src/main/res/drawable/point_shop_gradient_background.xml new file mode 100644 index 00000000..8f9e76f3 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_gradient_background.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/point_shop_selected_background.png b/app/src/main/res/drawable/point_shop_selected_background.png new file mode 100644 index 0000000000000000000000000000000000000000..65100be67c9759b448167bd358f7c0e49ead24a5 GIT binary patch literal 878 zcmV-!1CjiRP)}D#preHzB&>;^|ta&N$u$_ajV^9bGg6LG@q1{6XUGmbo4KE#6s6!CA zLXjBJ=*b9Tf({x5Q&{P&`#e3*tgG9yvyQfpAbvkEFVDOwJ71oeoq3*R^8L6&f-(eP zLfLX{S|^7r{+Iwvu*xHx08EnHN65e|OCV%m8bSufl{|zDO!C=47Bv}|BvkS%-yFk-C|GBz;gK7TY_T=u>bKnuD0o28zy_2|dfpHE)q zUuTkS3FoIJbRUm+7GXlAhzPuIa(-w2m_|?$;0QUUG4t$vCDb+ zX55L|kIA>=8M62^0kn>*?#(<^$4#-p(L64fU_zQ0ORG9;SiZZT!sQaoVmyP8fngFg z8JNb<#vcrmgx*SEnn1|FFwR_r3=CUC$iOHUoqNG7S?R50=kL96PoL@aI=efZYMXxD z);}4x7fXa~{b6rZTQ)=qR@Wof2Tk^EcHCe7?}&XG|E-mX?dy-jNP3)$TxDLF93ILr zA)CIxtnDyT31OnaHis#Wz36-r_2I=;YH~vB1>1z9RsYj|u@SIK*9x;j8?5In)A7w&pndiDabCf!t+> zYkiWp6aGF$!{c-H;Iw|3u=wUOPQnjpt26jWO^}-T3u)~cuW+koTL1t607*qoM6N<$ Ef=!E*_W%F@ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/point_shop_unselected_background.png b/app/src/main/res/drawable/point_shop_unselected_background.png new file mode 100644 index 0000000000000000000000000000000000000000..3a928e443215930f9839d1931d27a89469a23879 GIT binary patch literal 957 zcmV;u148_XP)LSK4E1Qu8Cr2YCX@4fc0l=gZhcMSIXNy_ye@7kt(bJzEKuds(V^)W@E7y$%ed?r1w zF-F&kSdsvOF|QCna7^(7A%h?xWN`AfJ2*78h zvQ62%b>rIo6+`SJWZ$2x8CLmoCs z#x_L@QJMfeIzHSZKZCWf`0|UfFHg#)J86Szm05sx;)5zB&-T;MQH}ch6nTpes5Cqj zqS2Aa+T5g`Xgo$n^6}J}*L+NnBmf^UW=~wcn||Qz%ZmT|ulePjoJ9bBux&P5e@0Wq zk0^^q_^|Zi)}IRH3Km&BZz6P}a%=H&h-er4;wJ77MpXiE5z$npKUvz4XES-Z9McoA ze4e(vKEmioFP%OSApkeLFdM%*n>OX;av^P)yeR8=l)1c`qowo?0k{ciG$FS2t1uR+ z1ETVapn)5Ou?uqRH1MKq$MrIgQw-3hc*R2J1AtilnJh&Iu<|)4Cr1IAh=oIx*bP~2 zzG}GYooo@%7!RWz~R}+x-YlNxGcxYWGgPeYkr(q zWm7ELo}Wt;-D}@Q+WR=ArtQ^(ho+4WG}TQ;d + android:background="@drawable/point_shop_gradient_background"> + + + + + + + app:layout_constraintTop_toBottomOf="@id/title_textview_point_shop" /> + + + + + + app:layout_constraintGuide_begin="44dp" /> + app:layout_constraintTop_toTopOf="@id/number_of_coins_textview" + app:layout_constraintEnd_toEndOf="@id/number_of_coins_textview" + app:layout_constraintBottom_toBottomOf="@id/number_of_coins_textview" + android:visibility="invisible"/> + android:src="@drawable/point_shop_currency" + app:layout_constraintEnd_toStartOf="@id/number_of_coins_textview" + app:layout_constraintTop_toTopOf="@id/number_of_coins_textview" + app:layout_constraintBottom_toBottomOf="@id/number_of_coins_textview" + android:visibility="invisible"/> - - + android:text="@string/blank" + android:visibility="invisible"/> + app:layout_constraintVertical_bias="0.0" /> #C5673F #903D2B #F9C126 + #741029 + #000000 + From 4e7c10fec4dfb5b233578f6da20fe2046ccd4066 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Sat, 1 Feb 2025 15:54:15 -0600 Subject: [PATCH 02/20] changes on 01/29 --- .../drawable/point_shop_cart_background.xml | 350 +++++++++++++ .../main/res/drawable/point_shop_cart_bg.png | Bin 0 -> 128731 bytes .../res/drawable/point_shop_cart_symbol.xml | 22 + .../point_shop_selected_background.png | Bin 878 -> 0 bytes .../point_shop_selected_background.xml | 19 + .../main/res/drawable/point_shop_sticker.xml | 10 + .../drawable/point_shop_sticker_symbol.xml | 483 ++++++++++++++++++ .../point_shop_unselected_background.png | Bin 957 -> 0 bytes .../point_shop_unselected_background.xml | 19 + app/src/main/res/layout/fragment_home.xml | 2 +- .../main/res/layout/fragment_point_shop.xml | 136 ++++- .../res/layout/fragment_point_shop_cart.xml | 274 ++++++++++ app/src/main/res/values/strings.xml | 1 + 13 files changed, 1314 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/point_shop_cart_background.xml create mode 100644 app/src/main/res/drawable/point_shop_cart_bg.png create mode 100644 app/src/main/res/drawable/point_shop_cart_symbol.xml delete mode 100644 app/src/main/res/drawable/point_shop_selected_background.png create mode 100644 app/src/main/res/drawable/point_shop_selected_background.xml create mode 100644 app/src/main/res/drawable/point_shop_sticker.xml create mode 100644 app/src/main/res/drawable/point_shop_sticker_symbol.xml delete mode 100644 app/src/main/res/drawable/point_shop_unselected_background.png create mode 100644 app/src/main/res/drawable/point_shop_unselected_background.xml create mode 100644 app/src/main/res/layout/fragment_point_shop_cart.xml diff --git a/app/src/main/res/drawable/point_shop_cart_background.xml b/app/src/main/res/drawable/point_shop_cart_background.xml new file mode 100644 index 00000000..1467b3f3 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_cart_background.xml @@ -0,0 +1,350 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_cart_bg.png b/app/src/main/res/drawable/point_shop_cart_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b258f2e4b07f39f75a1d01cd1ee5534af7657df4 GIT binary patch literal 128731 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%0D2)5~+HUL5q6%~!&Q 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/point_shop_cart_symbol.xml b/app/src/main/res/drawable/point_shop_cart_symbol.xml new file mode 100644 index 00000000..a69a0df1 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_cart_symbol.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_selected_background.png b/app/src/main/res/drawable/point_shop_selected_background.png deleted file mode 100644 index 65100be67c9759b448167bd358f7c0e49ead24a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 878 zcmV-!1CjiRP)}D#preHzB&>;^|ta&N$u$_ajV^9bGg6LG@q1{6XUGmbo4KE#6s6!CA zLXjBJ=*b9Tf({x5Q&{P&`#e3*tgG9yvyQfpAbvkEFVDOwJ71oeoq3*R^8L6&f-(eP zLfLX{S|^7r{+Iwvu*xHx08EnHN65e|OCV%m8bSufl{|zDO!C=47Bv}|BvkS%-yFk-C|GBz;gK7TY_T=u>bKnuD0o28zy_2|dfpHE)q zUuTkS3FoIJbRUm+7GXlAhzPuIa(-w2m_|?$;0QUUG4t$vCDb+ zX55L|kIA>=8M62^0kn>*?#(<^$4#-p(L64fU_zQ0ORG9;SiZZT!sQaoVmyP8fngFg z8JNb<#vcrmgx*SEnn1|FFwR_r3=CUC$iOHUoqNG7S?R50=kL96PoL@aI=efZYMXxD z);}4x7fXa~{b6rZTQ)=qR@Wof2Tk^EcHCe7?}&XG|E-mX?dy-jNP3)$TxDLF93ILr zA)CIxtnDyT31OnaHis#Wz36-r_2I=;YH~vB1>1z9RsYj|u@SIK*9x;j8?5In)A7w&pndiDabCf!t+> zYkiWp6aGF$!{c-H;Iw|3u=wUOPQnjpt26jWO^}-T3u)~cuW+koTL1t607*qoM6N<$ Ef=!E*_W%F@ diff --git a/app/src/main/res/drawable/point_shop_selected_background.xml b/app/src/main/res/drawable/point_shop_selected_background.xml new file mode 100644 index 00000000..fe41624a --- /dev/null +++ b/app/src/main/res/drawable/point_shop_selected_background.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/app/src/main/res/drawable/point_shop_sticker.xml b/app/src/main/res/drawable/point_shop_sticker.xml new file mode 100644 index 00000000..f5668dfd --- /dev/null +++ b/app/src/main/res/drawable/point_shop_sticker.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/point_shop_sticker_symbol.xml b/app/src/main/res/drawable/point_shop_sticker_symbol.xml new file mode 100644 index 00000000..b8e2a27e --- /dev/null +++ b/app/src/main/res/drawable/point_shop_sticker_symbol.xml @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_unselected_background.png b/app/src/main/res/drawable/point_shop_unselected_background.png deleted file mode 100644 index 3a928e443215930f9839d1931d27a89469a23879..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 957 zcmV;u148_XP)LSK4E1Qu8Cr2YCX@4fc0l=gZhcMSIXNy_ye@7kt(bJzEKuds(V^)W@E7y$%ed?r1w zF-F&kSdsvOF|QCna7^(7A%h?xWN`AfJ2*78h zvQ62%b>rIo6+`SJWZ$2x8CLmoCs z#x_L@QJMfeIzHSZKZCWf`0|UfFHg#)J86Szm05sx;)5zB&-T;MQH}ch6nTpes5Cqj zqS2Aa+T5g`Xgo$n^6}J}*L+NnBmf^UW=~wcn||Qz%ZmT|ulePjoJ9bBux&P5e@0Wq zk0^^q_^|Zi)}IRH3Km&BZz6P}a%=H&h-er4;wJ77MpXiE5z$npKUvz4XES-Z9McoA ze4e(vKEmioFP%OSApkeLFdM%*n>OX;av^P)yeR8=l)1c`qowo?0k{ciG$FS2t1uR+ z1ETVapn)5Ou?uqRH1MKq$MrIgQw-3hc*R2J1AtilnJh&Iu<|)4Cr1IAh=oIx*bP~2 zzG}GYooo@%7!RWz~R}+x-YlNxGcxYWGgPeYkr(q zWm7ELo}Wt;-D}@Q+WR=ArtQ^(ho+4WG}TQ;d + + + + + diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index cadbfbfb..43cbec63 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -203,7 +203,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - app:layout_constraintGuide_percent="0.055" /> + app:layout_constraintGuide_begin="40dp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_point_shop_cart.xml b/app/src/main/res/layout/fragment_point_shop_cart.xml new file mode 100644 index 00000000..19c4eccd --- /dev/null +++ b/app/src/main/res/layout/fragment_point_shop_cart.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd989af1..ca920bbf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -77,6 +77,7 @@ RAFFLE Unlimited Head to the Point Shop location to scan and buy items! + CART PROFILE PAGE From e6d4be4f5688e1b13c12c5b984b340b6d6dc508d Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Wed, 5 Feb 2025 17:54:41 -0600 Subject: [PATCH 03/20] changes on 2nd feb --- .../main/res/drawable/point_shop_borders.xml | 16 + .../main/res/drawable/point_shop_close.xml | 9 + .../res/drawable/point_shop_number_bar.xml | 9 + .../main/res/drawable/point_shop_redeem.xml | 22 + .../res/layout/fragment_point_shop_cart.xml | 833 +++++++++++++++--- app/src/main/res/values/strings.xml | 5 + 6 files changed, 780 insertions(+), 114 deletions(-) create mode 100644 app/src/main/res/drawable/point_shop_borders.xml create mode 100644 app/src/main/res/drawable/point_shop_close.xml create mode 100644 app/src/main/res/drawable/point_shop_number_bar.xml create mode 100644 app/src/main/res/drawable/point_shop_redeem.xml diff --git a/app/src/main/res/drawable/point_shop_borders.xml b/app/src/main/res/drawable/point_shop_borders.xml new file mode 100644 index 00000000..29d50b07 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_borders.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/drawable/point_shop_close.xml b/app/src/main/res/drawable/point_shop_close.xml new file mode 100644 index 00000000..40950ffb --- /dev/null +++ b/app/src/main/res/drawable/point_shop_close.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/point_shop_number_bar.xml b/app/src/main/res/drawable/point_shop_number_bar.xml new file mode 100644 index 00000000..92072875 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_number_bar.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/point_shop_redeem.xml b/app/src/main/res/drawable/point_shop_redeem.xml new file mode 100644 index 00000000..03673346 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_redeem.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/layout/fragment_point_shop_cart.xml b/app/src/main/res/layout/fragment_point_shop_cart.xml index 19c4eccd..8f7a5c54 100644 --- a/app/src/main/res/layout/fragment_point_shop_cart.xml +++ b/app/src/main/res/layout/fragment_point_shop_cart.xml @@ -88,12 +88,12 @@ android:src="@drawable/point_shop_sticker" android:adjustViewBounds="true" android:layout_marginStart="16dp" - app:layout_constraintWidth_percent="0.4" + app:layout_constraintWidth_percent="0.35" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/image_view_sticker2" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintVertical_bias="0.2" + app:layout_constraintVertical_bias="0.15" app:layout_constraintHorizontal_chainStyle="spread" /> - - - - - - - - - - - - + android:src="@drawable/point_shop_close" + app:layout_constraintBottom_toBottomOf="@id/image_view_sticker1" + app:layout_constraintEnd_toEndOf="@id/image_view_sticker1" + app:layout_constraintHeight_percent="0.035" + app:layout_constraintWidth_percent="0.035" + app:layout_constraintVertical_bias="0.05" + app:layout_constraintHorizontal_bias="0.07" + app:layout_constraintStart_toStartOf="@id/image_view_sticker1" + app:layout_constraintTop_toTopOf="@id/image_view_sticker1" /> - + android:src="@drawable/point_shop_close" + app:layout_constraintBottom_toBottomOf="@id/image_view_sticker2" + app:layout_constraintEnd_toEndOf="@id/image_view_sticker2" + app:layout_constraintHeight_percent="0.035" + app:layout_constraintWidth_percent="0.035" + app:layout_constraintVertical_bias="0.05" + app:layout_constraintHorizontal_bias="0.07" + app:layout_constraintStart_toStartOf="@id/image_view_sticker2" + app:layout_constraintTop_toTopOf="@id/image_view_sticker2" /> + - + - + + android:gravity="center" + android:src="@drawable/point_shop_borders" + app:layout_constraintStart_toStartOf="@id/image_view_number_bar1" + app:layout_constraintEnd_toEndOf="@id/image_view_number_bar1" + app:layout_constraintTop_toTopOf="@id/image_view_number_bar1" + app:layout_constraintBottom_toBottomOf="@id/image_view_number_bar1" /> + + + + + + + + + + + - + android:src="@drawable/point_shop_number_bar" + app:layout_constraintBottom_toBottomOf="@id/image_view_sticker2" + app:layout_constraintEnd_toEndOf="@id/image_view_sticker2" + app:layout_constraintStart_toStartOf="@id/image_view_sticker2" + app:layout_constraintTop_toTopOf="@id/image_view_sticker2" + app:layout_constraintVertical_bias="0.85" /> + + android:id="@+id/border2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:src="@drawable/point_shop_borders" + app:layout_constraintStart_toStartOf="@id/image_view_number_bar2" + app:layout_constraintEnd_toEndOf="@id/image_view_number_bar2" + app:layout_constraintTop_toTopOf="@id/image_view_number_bar2" + app:layout_constraintBottom_toBottomOf="@id/image_view_number_bar2" /> + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ca920bbf..d2f61844 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -78,6 +78,11 @@ Unlimited Head to the Point Shop location to scan and buy items! CART + Sticker + - + + + 1 + PROFILE PAGE From a75dcf25c56a6cc70876494ab5eab7dbe71091c6 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Wed, 5 Feb 2025 21:01:06 -0600 Subject: [PATCH 04/20] changes on 5th feb --- .../main/res/drawable/point_shop_back_bg.xml | 9 +++ .../main/res/drawable/point_shop_qr_code.xml | 9 +++ .../drawable/point_shop_sticker_coin_bg.xml | 9 +++ .../main/res/layout/fragment_point_shop.xml | 76 +++++++++++++++++++ .../res/layout/fragment_point_shop_cart.xml | 6 +- .../res/layout/fragment_point_shop_redeem.xml | 67 ++++++++++++++++ app/src/main/res/values/strings.xml | 3 + 7 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/drawable/point_shop_back_bg.xml create mode 100644 app/src/main/res/drawable/point_shop_qr_code.xml create mode 100644 app/src/main/res/drawable/point_shop_sticker_coin_bg.xml create mode 100644 app/src/main/res/layout/fragment_point_shop_redeem.xml diff --git a/app/src/main/res/drawable/point_shop_back_bg.xml b/app/src/main/res/drawable/point_shop_back_bg.xml new file mode 100644 index 00000000..05221243 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_back_bg.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/point_shop_qr_code.xml b/app/src/main/res/drawable/point_shop_qr_code.xml new file mode 100644 index 00000000..565b2915 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_qr_code.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/point_shop_sticker_coin_bg.xml b/app/src/main/res/drawable/point_shop_sticker_coin_bg.xml new file mode 100644 index 00000000..0e64891d --- /dev/null +++ b/app/src/main/res/drawable/point_shop_sticker_coin_bg.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/fragment_point_shop.xml b/app/src/main/res/layout/fragment_point_shop.xml index 4add9d42..6db99855 100644 --- a/app/src/main/res/layout/fragment_point_shop.xml +++ b/app/src/main/res/layout/fragment_point_shop.xml @@ -135,6 +135,35 @@ app:layout_constraintEnd_toEndOf="@id/image_view_sticker2" app:layout_constraintBottom_toBottomOf="@id/image_view_sticker2" app:layout_constraintTop_toTopOf="@id/image_view_sticker2" /> + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_point_shop_cart.xml b/app/src/main/res/layout/fragment_point_shop_cart.xml index 8f7a5c54..90e9f4f6 100644 --- a/app/src/main/res/layout/fragment_point_shop_cart.xml +++ b/app/src/main/res/layout/fragment_point_shop_cart.xml @@ -18,7 +18,7 @@ app:layout_constraintTop_toTopOf="parent"/> diff --git a/app/src/main/res/layout/fragment_point_shop_redeem.xml b/app/src/main/res/layout/fragment_point_shop_redeem.xml new file mode 100644 index 00000000..019c7b54 --- /dev/null +++ b/app/src/main/res/layout/fragment_point_shop_redeem.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d2f61844..3f19150a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -82,6 +82,9 @@ - + 1 + BACK + SCAN HERE TO \nCOMPLETE PURCHASE + From 266a084331212ea83ee771f40ad55e3a36e4bd9f Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Wed, 5 Feb 2025 21:14:15 -0600 Subject: [PATCH 05/20] changes on 5th feb --- app/src/main/res/drawable/point_shop_qr_code.xml | 9 --------- app/src/main/res/layout/fragment_point_shop_redeem.xml | 8 ++++---- 2 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 app/src/main/res/drawable/point_shop_qr_code.xml diff --git a/app/src/main/res/drawable/point_shop_qr_code.xml b/app/src/main/res/drawable/point_shop_qr_code.xml deleted file mode 100644 index 565b2915..00000000 --- a/app/src/main/res/drawable/point_shop_qr_code.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/fragment_point_shop_redeem.xml b/app/src/main/res/layout/fragment_point_shop_redeem.xml index 019c7b54..eb4f390b 100644 --- a/app/src/main/res/layout/fragment_point_shop_redeem.xml +++ b/app/src/main/res/layout/fragment_point_shop_redeem.xml @@ -50,10 +50,10 @@ app:layout_constraintHorizontal_bias="0.5" /> Date: Thu, 13 Feb 2025 06:11:52 -0600 Subject: [PATCH 06/20] points shop without api logic --- .../main/java/org/hackillinois/android/API.kt | 10 + .../android/database/entity/Cart.kt | 10 + .../android/database/entity/QRResponse.kt | 3 + .../android/database/entity/ShopItem.kt | 4 + .../android/view/shop/CartAdapter.kt | 55 ++ .../android/view/shop/CartFragment.kt | 65 ++ .../android/view/shop/RedeemFragment.kt | 66 ++ .../android/view/shop/ShopAdapter.kt | 34 +- .../android/view/shop/ShopFragment.kt | 17 +- .../android/viewmodel/ScheduleViewModel.kt | 8 +- .../res/drawable/point_shop_back_circle.xml | 10 + .../res/drawable/point_shop_back_symbol.png | Bin 0 -> 261 bytes .../res/drawable/point_shop_cart_symbol.xml | 5 +- .../res/drawable/point_shop_plus_button.xml | 16 + .../main/res/layout/fragment_point_shop.xml | 317 ++++--- .../res/layout/fragment_point_shop_cart.xml | 832 +----------------- .../res/layout/fragment_point_shop_redeem.xml | 6 +- .../main/res/layout/point_shop_cart_tile.xml | 123 +++ app/src/main/res/layout/point_shop_tile.xml | 159 ++++ app/src/main/res/values/colors.xml | 2 +- 20 files changed, 790 insertions(+), 952 deletions(-) create mode 100644 app/src/main/java/org/hackillinois/android/database/entity/Cart.kt create mode 100644 app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt create mode 100644 app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt create mode 100644 app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt create mode 100644 app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt create mode 100644 app/src/main/res/drawable/point_shop_back_circle.xml create mode 100644 app/src/main/res/drawable/point_shop_back_symbol.png create mode 100644 app/src/main/res/drawable/point_shop_plus_button.xml create mode 100644 app/src/main/res/layout/point_shop_cart_tile.xml create mode 100644 app/src/main/res/layout/point_shop_tile.xml diff --git a/app/src/main/java/org/hackillinois/android/API.kt b/app/src/main/java/org/hackillinois/android/API.kt index def0c043..270249c3 100644 --- a/app/src/main/java/org/hackillinois/android/API.kt +++ b/app/src/main/java/org/hackillinois/android/API.kt @@ -1,5 +1,6 @@ package org.hackillinois.android +import okhttp3.ResponseBody import org.hackillinois.android.database.entity.* import org.hackillinois.android.model.event.EventsList import org.hackillinois.android.model.event.ShiftsList @@ -68,6 +69,15 @@ interface API { @POST("shop/item/buy/") suspend fun buyShopItem(@Body body: ItemInstance): ShopItem + @POST("shop/cart/{itemId}") + fun addItemCart(@Path("itemId") itemId : String) : Call + + @GET("shop/cart/") + suspend fun getCart(): Cart + + @GET("shop/cart/qr/") + suspend fun getCartQRCode(): QRResponse + // STAFF @POST("staff/attendance/") diff --git a/app/src/main/java/org/hackillinois/android/database/entity/Cart.kt b/app/src/main/java/org/hackillinois/android/database/entity/Cart.kt new file mode 100644 index 00000000..0cedf42e --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/database/entity/Cart.kt @@ -0,0 +1,10 @@ +package org.hackillinois.android.database.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "cart") +data class Cart( + @PrimaryKey val userId: String, + val items: Map // Maps itemId to quantity +) diff --git a/app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt b/app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt new file mode 100644 index 00000000..f60a8700 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt @@ -0,0 +1,3 @@ +package org.hackillinois.android.database.entity + +data class QRResponse(val qrCode: String) diff --git a/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt b/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt index 5111d560..cc9780cc 100644 --- a/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt +++ b/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt @@ -15,3 +15,7 @@ data class ShopItem( var quantity: Int, var imageURL: String, ) + + + + diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt new file mode 100644 index 00000000..92005f47 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt @@ -0,0 +1,55 @@ +package org.hackillinois.android.view.shop + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import org.hackillinois.android.R +import org.hackillinois.android.database.entity.ShopItem + +class CartAdapter(private var cartItems: List>) : + RecyclerView.Adapter() { + + private lateinit var context: Context + + inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val view = LayoutInflater.from(parent.context).inflate(R.layout.point_shop_cart_tile, parent, false) + context = parent.context + return ViewHolder(view) + } + + override fun getItemCount() = cartItems.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val (item, quantity) = cartItems[position] + bind(item, quantity, holder.itemView) + } + + private fun bind(item: ShopItem, quantity: Int, itemView: View) { + itemView.apply { + val textViewSticker: TextView = findViewById(R.id.text_view_sticker) + textViewSticker.text = item.name + val quantiyTextView: TextView = findViewById(R.id.number_text) + quantiyTextView.text = quantity.toString() + + val shopItemImageView: ImageView = findViewById(R.id.image_view_sticker_symbol) + Glide.with(context).load(item.imageURL).into(shopItemImageView) +// +// val plusButton: ImageView = findViewById(R.id.button_plus) +// plusButton.setOnClickListener { +// // Logic to increase quantity in the cart +// } + } + } + + fun updateCart(newCartItems: List>) { + this.cartItems = newCartItems + notifyDataSetChanged() + } +} diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt new file mode 100644 index 00000000..b5abb902 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt @@ -0,0 +1,65 @@ +package org.hackillinois.android.view.shop + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import org.hackillinois.android.R +import org.hackillinois.android.database.entity.ShopItem + + +class CartFragment : Fragment() { + + private lateinit var recyclerView: RecyclerView + private lateinit var cartAdapter: CartAdapter + private var cartItems: List> = listOf() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_point_shop_cart, container, false) + + recyclerView = view.findViewById(R.id.recyclerview_point_shop) + recyclerView.layoutManager = GridLayoutManager(context, 2) + + cartAdapter = CartAdapter(cartItems) + recyclerView.adapter = cartAdapter + + fetchCartData() + + val backButton: View = view.findViewById(R.id.backButton) + backButton.bringToFront() + backButton.setOnClickListener { + requireActivity().supportFragmentManager.popBackStack() // Go back to the previous fragment + } + + // Handle Redeem Button Click + val redeemButton: View = view.findViewById(R.id.redeemButton) + redeemButton.setOnClickListener { + val redeemFragment = RedeemFragment() + requireActivity().supportFragmentManager.beginTransaction() + .replace(R.id.contentFrame, redeemFragment) + .addToBackStack(null) // Allows back navigation + .commit() + } + + + return view + + } + + private fun fetchCartData() { + // random example to see the layout + cartItems = listOf( + Pair(ShopItem("1", "T-Shirt", 10, false, 1, "https://example.com/tshirt.png"), 2), + Pair(ShopItem("2", "Sticker", 5, false, 1, "https://example.com/sticker.png"), 3) + ) + cartAdapter.updateCart(cartItems) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt new file mode 100644 index 00000000..203e40ce --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt @@ -0,0 +1,66 @@ +package org.hackillinois.android.view.shop + +import android.graphics.Bitmap +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.fragment.app.Fragment +import com.google.zxing.BarcodeFormat +import com.google.zxing.MultiFormatWriter +import com.google.zxing.common.BitMatrix +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.hackillinois.android.App +import org.hackillinois.android.R +import org.hackillinois.android.common.QRUtilities.Companion.generateQRCode +import org.hackillinois.android.database.entity.QRResponse + +class RedeemFragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_point_shop_redeem, container, false) + + // Handle Back Button Click + val backButton: View = view.findViewById(R.id.title_textview_back) + backButton.bringToFront() + backButton.setOnClickListener { + requireActivity().supportFragmentManager.popBackStack() // Go back to previous fragment + } + +// fun fetchQRCode(qrImageView: ImageView) { +// CoroutineScope(Dispatchers.IO).launch { +// try { +// val response: QRResponse = App.getAPI().getCartQRCode() +// val qrBitmap = generateQRCode(response.qrCode) +// +// requireActivity().runOnUiThread { +// qrImageView.setImageBitmap(qrBitmap) +// } +// } catch (e: Exception) { +// e.printStackTrace() +// } +// } +// } +// +// fun generateQRCode(text: String): Bitmap { +// val size = 512 // QR code size +// val bitMatrix: BitMatrix = MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, size, size) +// val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565) +// +// for (x in 0 until size) { +// for (y in 0 until size) { +// bitmap.setPixel(x, y, if (bitMatrix[x, y]) Color.BLACK else Color.WHITE) +// } +// } +// +// return bitmap + return view + } + } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 1ca447b2..17e6b441 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -11,6 +11,7 @@ import android.widget.Toast import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.shop_tile.view.* +import org.hackillinois.android.App import org.hackillinois.android.R import org.hackillinois.android.database.entity.ShopItem @@ -22,7 +23,7 @@ class ShopAdapter(private var itemList: List) : // onCreateViewHolder used to display scrollable list of items // implemented as part of RecyclerView's adapter, responsible for creating new ViewHolder objects override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val layoutResource = R.layout.shop_tile + val layoutResource = R.layout.point_shop_tile val view = LayoutInflater.from(parent.context).inflate(layoutResource, parent, false) val viewHolder = ViewHolder(view) context = parent.context @@ -37,25 +38,14 @@ class ShopAdapter(private var itemList: List) : // populating views within ViewHolder with data from 'item' // position is zero-indexed but we want the leaderboard to start at 1 bind(item, holder.itemView, position + 1) + + } private fun bind(item: ShopItem, itemView: View, position: Int) { itemView.apply { - // set on click listener on item price + quantity "button" section - shopItemListenerView.setOnClickListener { - Toast.makeText(itemView.context, R.string.shop_toast_text, Toast.LENGTH_SHORT).show() - } - - // set the top brown divider for the first item to be visible - if (position == 1) { - val topDivider: TextView = itemView.findViewById(R.id.brownDividerTop) - topDivider.visibility = View.VISIBLE - } else { - val topDivider: TextView = itemView.findViewById(R.id.brownDividerTop) - topDivider.visibility = View.GONE - } - - shopItemTextView.text = item.name + val textViewSticker: TextView = findViewById(R.id.text_view_sticker) + textViewSticker.text = item.name priceTextView.text = item.price.toString() val quantity = item.quantity @@ -65,14 +55,22 @@ class ShopAdapter(private var itemList: List) : quantityTextView.text = resources.getString(R.string.shopquantity, quantity) } - val shopItemImageView: ImageView = itemView.findViewById(R.id.shopItemImageView) + val shopItemImageView: ImageView = itemView.findViewById(R.id.image_view_sticker_symbol) try { Glide.with(context).load(item.imageURL).into(shopItemImageView) } catch (e: Exception) { Log.d("Shop Glide Error", e.message.toString()) } + val plusButton: ImageView = findViewById(R.id.plusButton) + plusButton.setOnClickListener { + Log.d("CartDebug", "Plus button clicked!") + App.getAPI().addItemCart(item.itemId) + } + + } + } - } + fun updateShop(shopItem: List) { this.itemList = shopItem diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index 065fc596..98f16d1b 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -15,6 +15,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.fragment_point_shop.number_of_coins_textview import kotlinx.android.synthetic.main.fragment_point_shop.view.recyclerview_point_shop +import android.util.Log import org.hackillinois.android.R import org.hackillinois.android.common.JWTUtilities import org.hackillinois.android.database.entity.Profile @@ -74,7 +75,7 @@ class ShopFragment : Fragment() { mAdapter = ShopAdapter(shop) recyclerView = view.recyclerview_point_shop.apply { - mLayoutManager = LinearLayoutManager(context) + mLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) this.layoutManager = mLayoutManager this.adapter = mAdapter } @@ -107,9 +108,23 @@ class ShopFragment : Fragment() { ) } + val cartTextView: TextView = view.findViewById(R.id.text_view_cart) + cartTextView.bringToFront() + + cartTextView.setOnClickListener { + Log.d("ShopFragment", "Cart image clicked") + val cartFragment = CartFragment() + val transaction = requireActivity().supportFragmentManager.beginTransaction() + transaction.replace(R.id.contentFrame, cartFragment) + transaction.addToBackStack(null) // Optional, for back navigation + transaction.commit() + } + return view } + + // Called in onCreateView within shopLiveData.observe private fun updateShopItems(newShop: List) { // Split the shop items into Merch and Raffle items diff --git a/app/src/main/java/org/hackillinois/android/viewmodel/ScheduleViewModel.kt b/app/src/main/java/org/hackillinois/android/viewmodel/ScheduleViewModel.kt index d2a753be..46ea3ea0 100644 --- a/app/src/main/java/org/hackillinois/android/viewmodel/ScheduleViewModel.kt +++ b/app/src/main/java/org/hackillinois/android/viewmodel/ScheduleViewModel.kt @@ -15,25 +15,25 @@ class ScheduleViewModel : ViewModel() { // 2/23/24 00:00:00 val fridayStart = Calendar.getInstance().apply { timeZone = TimeZone.getTimeZone("America/Chicago") - timeInMillis = 1708668000000 + timeInMillis = 1740722400000 }.timeInMillis // 2/23/24 23:59:59 val fridayEnd = Calendar.getInstance().apply { timeZone = TimeZone.getTimeZone("America/Chicago") - timeInMillis = 1708754399000 + timeInMillis = 1740808799000 }.timeInMillis // 2/24/24 23:59:59 val saturdayEnd = Calendar.getInstance().apply { timeZone = TimeZone.getTimeZone("America/Chicago") - timeInMillis = 1708840799000 + timeInMillis = 1740895199000 }.timeInMillis // 2/25/24 23:59:59 val sundayEnd = Calendar.getInstance().apply { timeZone = TimeZone.getTimeZone("America/Chicago") - timeInMillis = 1708927199000 + timeInMillis = 1740895199000 }.timeInMillis var fridayEventsLiveData = eventRepository.fetchEventsHappeningBetweenTimes(fridayStart, fridayEnd) diff --git a/app/src/main/res/drawable/point_shop_back_circle.xml b/app/src/main/res/drawable/point_shop_back_circle.xml new file mode 100644 index 00000000..4eedd9d6 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_back_circle.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/point_shop_back_symbol.png b/app/src/main/res/drawable/point_shop_back_symbol.png new file mode 100644 index 0000000000000000000000000000000000000000..7e0984188b738f76bb4a07a4a8c66137d791e27c GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^${@_a1|;QfZjJ;}oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{wz-y$B+ufx6|%&HXBH|uFs9Pa$o-1;_gD@ zk`}!S)5UhREKt&TAu9aE@ekw2?h1Yxrpl8Km0K8`I5yfVZJ(FW!{7Omo4fg3M8DdS zMVxytNuPZoE&W*iQj5qrdmahy&JBuOfhS^`I4dv7yqz5s+4iHkev6Cs%r)Ed-7Yw; zynVUlmqtd{LhF=M;;|QG89yxKuX0qF@xQUvLeEsG!fE|=lNDM(S2B3I`njxgN@xNA DiHBPv literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/point_shop_cart_symbol.xml b/app/src/main/res/drawable/point_shop_cart_symbol.xml index a69a0df1..953aba5b 100644 --- a/app/src/main/res/drawable/point_shop_cart_symbol.xml +++ b/app/src/main/res/drawable/point_shop_cart_symbol.xml @@ -10,13 +10,10 @@ android:pathData="M51.282,0.104L37.814,24.398H49.418L60.814,0.104H51.282Z" android:fillColor="#FFE4A5"/> - diff --git a/app/src/main/res/drawable/point_shop_plus_button.xml b/app/src/main/res/drawable/point_shop_plus_button.xml new file mode 100644 index 00000000..cfb37f11 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_plus_button.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/layout/fragment_point_shop.xml b/app/src/main/res/layout/fragment_point_shop.xml index 6db99855..7cbae687 100644 --- a/app/src/main/res/layout/fragment_point_shop.xml +++ b/app/src/main/res/layout/fragment_point_shop.xml @@ -32,19 +32,25 @@ app:layout_constraintTop_toTopOf="@id/image_view_counter" app:layout_constraintVertical_bias="0.30"/> - + app:layout_constraintVertical_bias="0.44" /> - @@ -147,7 +155,7 @@ app:layout_constraintEnd_toEndOf="@id/image_view_sticker1" app:layout_constraintStart_toStartOf="@id/image_view_sticker1" app:layout_constraintTop_toTopOf="@id/image_view_sticker1" - app:layout_constraintVertical_bias="0.1" + app:layout_constraintVertical_bias="0.125" app:layout_constraintHorizontal_bias="0.5" /> + - - - + - + - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + app:layout_constraintVertical_bias="0.80" /> + /> + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_point_shop_redeem.xml b/app/src/main/res/layout/fragment_point_shop_redeem.xml index eb4f390b..ffee1af2 100644 --- a/app/src/main/res/layout/fragment_point_shop_redeem.xml +++ b/app/src/main/res/layout/fragment_point_shop_redeem.xml @@ -7,10 +7,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/point_shop_tile.xml b/app/src/main/res/layout/point_shop_tile.xml new file mode 100644 index 00000000..f7358da0 --- /dev/null +++ b/app/src/main/res/layout/point_shop_tile.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 900ec499..998d2f91 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -56,6 +56,6 @@ #F9C126 #741029 #000000 - + #612547 From b20540bd3a001936628acee4484b3537dc53cea2 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Thu, 13 Feb 2025 14:26:34 -0600 Subject: [PATCH 07/20] points shop without api logic --- .../android/view/shop/RedeemFragment.kt | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt index 203e40ce..53e74a92 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt @@ -1,23 +1,11 @@ package org.hackillinois.android.view.shop -import android.graphics.Bitmap -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ImageView import androidx.fragment.app.Fragment -import com.google.zxing.BarcodeFormat -import com.google.zxing.MultiFormatWriter -import com.google.zxing.common.BitMatrix -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import org.hackillinois.android.App import org.hackillinois.android.R -import org.hackillinois.android.common.QRUtilities.Companion.generateQRCode -import org.hackillinois.android.database.entity.QRResponse class RedeemFragment : Fragment() { @@ -33,34 +21,6 @@ class RedeemFragment : Fragment() { backButton.setOnClickListener { requireActivity().supportFragmentManager.popBackStack() // Go back to previous fragment } - -// fun fetchQRCode(qrImageView: ImageView) { -// CoroutineScope(Dispatchers.IO).launch { -// try { -// val response: QRResponse = App.getAPI().getCartQRCode() -// val qrBitmap = generateQRCode(response.qrCode) -// -// requireActivity().runOnUiThread { -// qrImageView.setImageBitmap(qrBitmap) -// } -// } catch (e: Exception) { -// e.printStackTrace() -// } -// } -// } -// -// fun generateQRCode(text: String): Bitmap { -// val size = 512 // QR code size -// val bitMatrix: BitMatrix = MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, size, size) -// val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565) -// -// for (x in 0 until size) { -// for (y in 0 until size) { -// bitmap.setPixel(x, y, if (bitMatrix[x, y]) Color.BLACK else Color.WHITE) -// } -// } -// -// return bitmap return view } } From d075a7522ffe8b627836d3c154b115ea302f3251 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Thu, 13 Feb 2025 14:33:30 -0600 Subject: [PATCH 08/20] points shop without api logic --- app/src/main/java/org/hackillinois/android/API.kt | 2 +- .../hackillinois/android/database/entity/ShopItem.kt | 4 ---- .../org/hackillinois/android/view/shop/CartFragment.kt | 10 +++------- .../hackillinois/android/view/shop/RedeemFragment.kt | 8 +++----- .../org/hackillinois/android/view/shop/ShopAdapter.kt | 2 -- 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/API.kt b/app/src/main/java/org/hackillinois/android/API.kt index 270249c3..941772b8 100644 --- a/app/src/main/java/org/hackillinois/android/API.kt +++ b/app/src/main/java/org/hackillinois/android/API.kt @@ -70,7 +70,7 @@ interface API { suspend fun buyShopItem(@Body body: ItemInstance): ShopItem @POST("shop/cart/{itemId}") - fun addItemCart(@Path("itemId") itemId : String) : Call + fun addItemCart(@Path("itemId") itemId: String) : Call @GET("shop/cart/") suspend fun getCart(): Cart diff --git a/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt b/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt index cc9780cc..5111d560 100644 --- a/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt +++ b/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt @@ -15,7 +15,3 @@ data class ShopItem( var quantity: Int, var imageURL: String, ) - - - - diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt index b5abb902..da244090 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt @@ -17,10 +17,8 @@ class CartFragment : Fragment() { private lateinit var cartAdapter: CartAdapter private var cartItems: List> = listOf() - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_point_shop_cart, container, false) recyclerView = view.findViewById(R.id.recyclerview_point_shop) @@ -60,6 +58,4 @@ class CartFragment : Fragment() { ) cartAdapter.updateCart(cartItems) } - - -} \ No newline at end of file +} diff --git a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt index 53e74a92..dcdfc196 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt @@ -9,10 +9,8 @@ import org.hackillinois.android.R class RedeemFragment : Fragment() { - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_point_shop_redeem, container, false) // Handle Back Button Click @@ -22,5 +20,5 @@ class RedeemFragment : Fragment() { requireActivity().supportFragmentManager.popBackStack() // Go back to previous fragment } return view - } } +} diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 17e6b441..06dcd8dc 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -7,7 +7,6 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView -import android.widget.Toast import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.shop_tile.view.* @@ -71,7 +70,6 @@ class ShopAdapter(private var itemList: List) : } - fun updateShop(shopItem: List) { this.itemList = shopItem notifyDataSetChanged() From 985b43c3e59c98ba7b8feea8e96851364fd7cb38 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Thu, 13 Feb 2025 14:38:15 -0600 Subject: [PATCH 09/20] points shop without api logic --- .../android/view/shop/ShopAdapter.kt | 4 +- .../android/view/shop/ShopFragment.kt | 40 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 06dcd8dc..495efd64 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -66,10 +66,10 @@ class ShopAdapter(private var itemList: List) : App.getAPI().addItemCart(item.itemId) } - } - } + } + fun updateShop(shopItem: List) { this.itemList = shopItem notifyDataSetChanged() diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index 98f16d1b..a54d0192 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -66,7 +66,11 @@ class ShopFragment : Fragment() { } } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { val view = inflater.inflate(R.layout.fragment_point_shop, container, false) merchButton = view.findViewById(R.id.merchButton) @@ -119,12 +123,9 @@ class ShopFragment : Fragment() { transaction.addToBackStack(null) // Optional, for back navigation transaction.commit() } - return view } - - // Called in onCreateView within shopLiveData.observe private fun updateShopItems(newShop: List) { // Split the shop items into Merch and Raffle items @@ -145,9 +146,19 @@ class ShopFragment : Fragment() { private val merchClickListener = View.OnClickListener { if (!merchButton.isSelected) { merchButton.isSelected = true - merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_selected_background) } + merchButton.background = this.context?.let { it1 -> + ContextCompat.getDrawable( + it1, + R.drawable.point_shop_selected_background + ) + } raffleButton.isSelected = false - raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_unselected_background) } + raffleButton.background = this.context?.let { it1 -> + ContextCompat.getDrawable( + it1, + R.drawable.point_shop_unselected_background + ) + } showingMerch = true updateShopUI() } @@ -157,9 +168,19 @@ class ShopFragment : Fragment() { private val raffleClickListener = View.OnClickListener { if (!raffleButton.isSelected) { raffleButton.isSelected = true - raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_selected_background) } + raffleButton.background = this.context?.let { it1 -> + ContextCompat.getDrawable( + it1, + R.drawable.point_shop_selected_background + ) + } merchButton.isSelected = false - merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.point_shop_unselected_background) } + merchButton.background = this.context?.let { it1 -> + ContextCompat.getDrawable( + it1, + R.drawable.point_shop_unselected_background + ) + } showingMerch = false updateShopUI() } @@ -179,6 +200,7 @@ class ShopFragment : Fragment() { private fun isAttendee(): Boolean { val context = requireActivity().applicationContext val prefString = context.getString(R.string.authorization_pref_file_key) - return context.getSharedPreferences(prefString, Context.MODE_PRIVATE).getString("provider", "") ?: "" == "github" + return context.getSharedPreferences(prefString, Context.MODE_PRIVATE) + .getString("provider", "") ?: "" == "github" } } From a637c06d073957de9476ea2df563a459fa9e57b7 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Thu, 13 Feb 2025 14:44:27 -0600 Subject: [PATCH 10/20] points shop without api logic --- app/src/main/java/org/hackillinois/android/API.kt | 2 +- .../org/hackillinois/android/view/shop/CartFragment.kt | 10 +++++----- .../hackillinois/android/view/shop/RedeemFragment.kt | 7 +++++-- .../org/hackillinois/android/view/shop/ShopAdapter.kt | 4 ---- .../org/hackillinois/android/view/shop/ShopFragment.kt | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/API.kt b/app/src/main/java/org/hackillinois/android/API.kt index 941772b8..ec29ec8d 100644 --- a/app/src/main/java/org/hackillinois/android/API.kt +++ b/app/src/main/java/org/hackillinois/android/API.kt @@ -70,7 +70,7 @@ interface API { suspend fun buyShopItem(@Body body: ItemInstance): ShopItem @POST("shop/cart/{itemId}") - fun addItemCart(@Path("itemId") itemId: String) : Call + fun addItemCart(@Path("itemId") itemId: String): Call @GET("shop/cart/") suspend fun getCart(): Cart diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt index da244090..6a6a1e4b 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt @@ -10,15 +10,17 @@ import androidx.recyclerview.widget.RecyclerView import org.hackillinois.android.R import org.hackillinois.android.database.entity.ShopItem - class CartFragment : Fragment() { private lateinit var recyclerView: RecyclerView private lateinit var cartAdapter: CartAdapter private var cartItems: List> = listOf() - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { val view = inflater.inflate(R.layout.fragment_point_shop_cart, container, false) recyclerView = view.findViewById(R.id.recyclerview_point_shop) @@ -45,9 +47,7 @@ class CartFragment : Fragment() { .commit() } - return view - } private fun fetchCartData() { diff --git a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt index dcdfc196..211a8318 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt @@ -9,8 +9,11 @@ import org.hackillinois.android.R class RedeemFragment : Fragment() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { val view = inflater.inflate(R.layout.fragment_point_shop_redeem, container, false) // Handle Back Button Click diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 495efd64..d98960d3 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -37,8 +37,6 @@ class ShopAdapter(private var itemList: List) : // populating views within ViewHolder with data from 'item' // position is zero-indexed but we want the leaderboard to start at 1 bind(item, holder.itemView, position + 1) - - } private fun bind(item: ShopItem, itemView: View, position: Int) { @@ -65,9 +63,7 @@ class ShopAdapter(private var itemList: List) : Log.d("CartDebug", "Plus button clicked!") App.getAPI().addItemCart(item.itemId) } - } - } fun updateShop(shopItem: List) { diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index a54d0192..42f1c99f 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -2,6 +2,7 @@ package org.hackillinois.android.view.shop import android.content.Context import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -15,7 +16,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.fragment_point_shop.number_of_coins_textview import kotlinx.android.synthetic.main.fragment_point_shop.view.recyclerview_point_shop -import android.util.Log import org.hackillinois.android.R import org.hackillinois.android.common.JWTUtilities import org.hackillinois.android.database.entity.Profile From cff102b7dd003d9915bc0e8a95fe98a48214aaf9 Mon Sep 17 00:00:00 2001 From: Aditya Kshirsagar Date: Fri, 14 Feb 2025 15:10:24 -0600 Subject: [PATCH 11/20] fixed adding to cart API endpoint --- .../main/java/org/hackillinois/android/API.kt | 3 +- .../main/java/org/hackillinois/android/App.kt | 5 +- .../android/view/shop/ShopAdapter.kt | 53 ++++++++++++++++++- .../android/view/shop/ShopFragment.kt | 24 ++++++++- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/API.kt b/app/src/main/java/org/hackillinois/android/API.kt index ec29ec8d..0e4278fe 100644 --- a/app/src/main/java/org/hackillinois/android/API.kt +++ b/app/src/main/java/org/hackillinois/android/API.kt @@ -16,6 +16,7 @@ import org.hackillinois.android.model.user.FavoritesResponse import org.hackillinois.android.model.version.Version import org.hackillinois.android.notifications.DeviceToken import retrofit2.Call +import retrofit2.Response import retrofit2.http.* interface API { @@ -70,7 +71,7 @@ interface API { suspend fun buyShopItem(@Body body: ItemInstance): ShopItem @POST("shop/cart/{itemId}") - fun addItemCart(@Path("itemId") itemId: String): Call + suspend fun addItemCart(@Path("itemId") itemId: String): Response @GET("shop/cart/") suspend fun getCart(): Cart diff --git a/app/src/main/java/org/hackillinois/android/App.kt b/app/src/main/java/org/hackillinois/android/App.kt index fba00533..2c8d8849 100644 --- a/app/src/main/java/org/hackillinois/android/App.kt +++ b/app/src/main/java/org/hackillinois/android/App.kt @@ -30,11 +30,12 @@ class App : Application() { return if (apiInitialized) apiInternal else getAPI("") } - Log.d("TOKEN", token) + Log.d("APPTOKEN", token) val interceptor = { chain: Interceptor.Chain -> val newRequest = chain.request().newBuilder() - .addHeader("Authorization", token) + .addHeader("Authorization", "Bearer $token") + .addHeader("Accept", "application/json") .build() chain.proceed(newRequest) } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index d98960d3..ac0d9289 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -7,18 +7,27 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import androidx.lifecycle.findViewTreeLifecycleOwner import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.shop_tile.view.* +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import okhttp3.ResponseBody import org.hackillinois.android.App import org.hackillinois.android.R import org.hackillinois.android.database.entity.ShopItem +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.launch -class ShopAdapter(private var itemList: List) : +class ShopAdapter(private var itemList: List, private val buyItemListener : OnBuyItemListener) : RecyclerView.Adapter() { private lateinit var context: Context inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) + + // onCreateViewHolder used to display scrollable list of items // implemented as part of RecyclerView's adapter, responsible for creating new ViewHolder objects override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { @@ -59,9 +68,45 @@ class ShopAdapter(private var itemList: List) : Log.d("Shop Glide Error", e.message.toString()) } val plusButton: ImageView = findViewById(R.id.plusButton) + +// plusButton.setOnClickListener { +// Log.d("CartDebug", "Plus button clicked!") +// Log.d("Item ID: ", ""+item.itemId) +// App.getAPI().addItemCart(item.itemId).enqueue(object : Callback { +// override fun onResponse(call: Call, response: Response) { +// if (response.isSuccessful) { +// Log.d("CartDebug", "Item added to cart successfully!: ${response.code()}, ${response.message()}, ${response.body().toString()}") +// } else { +// Log.e("CartDebug", "Failed to add item: ${response.code()}") +// } +// } +// +// override fun onFailure(call: Call, t: Throwable) { +// Log.e("CartDebug", "Error adding item to cart", t) +// } +// }) +// } +// plusButton.setOnClickListener { +// Log.d("CartDebug", "Plus button clicked!") +// Log.d("Item ID: ", ""+item.itemId) +// itemView.findViewTreeLifecycleOwner()?.lifecycleScope?.launch { +// try { +// val response = App.getAPI().addItemCart(item.itemId) +// if (response.isSuccessful) { +// val cartResponse = response.body() +// Log.d("CartDebug", "Item added: $cartResponse") +// } else { +// Log.e("CartDebug", "Failed to add item: ${response.code()}") +// } +// } catch (e: Exception) { +// Log.e("CartDebug", "Error adding item to cart", e) +// } +// } ?: Log.e("CartDebug", "No LifecycleOwner found for itemView") +// } plusButton.setOnClickListener { Log.d("CartDebug", "Plus button clicked!") - App.getAPI().addItemCart(item.itemId) + Log.d("Item ID: ", ""+item.itemId) + buyItemListener.onBuyItem(item) } } } @@ -70,4 +115,8 @@ class ShopAdapter(private var itemList: List) : this.itemList = shopItem notifyDataSetChanged() } + + interface OnBuyItemListener { + fun onBuyItem(item : ShopItem) + } } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index 42f1c99f..77b30e34 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -12,17 +12,20 @@ import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.fragment_point_shop.number_of_coins_textview import kotlinx.android.synthetic.main.fragment_point_shop.view.recyclerview_point_shop +import kotlinx.coroutines.launch +import org.hackillinois.android.App 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.viewmodel.ShopViewModel -class ShopFragment : Fragment() { +class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { companion object { fun newInstance() = ShopFragment() @@ -76,7 +79,7 @@ class ShopFragment : Fragment() { merchButton = view.findViewById(R.id.merchButton) raffleButton = view.findViewById(R.id.raffleButton) - mAdapter = ShopAdapter(shop) + mAdapter = ShopAdapter(shop, this) recyclerView = view.recyclerview_point_shop.apply { mLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) @@ -203,4 +206,21 @@ class ShopFragment : Fragment() { return context.getSharedPreferences(prefString, Context.MODE_PRIVATE) .getString("provider", "") ?: "" == "github" } + + override fun onBuyItem(item: ShopItem) { + // Implement your buying logic here (e.g., make a network call) + lifecycleScope.launch { + 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()}") + } else { + Log.e("CartDebug", "Failed to add item: ${response.code()}") + } + } catch (e: Exception) { + Log.e("CartDebug", "Error adding item to cart", e) + } + } + } } From ff56b9b17f4392feb37a6889e474af50e3b2db95 Mon Sep 17 00:00:00 2001 From: Aditya Kshirsagar Date: Fri, 14 Feb 2025 15:13:55 -0600 Subject: [PATCH 12/20] fixed ktlint issues --- .../android/view/shop/ShopAdapter.kt | 48 ++----------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index ac0d9289..085b6350 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -7,21 +7,13 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView -import androidx.lifecycle.findViewTreeLifecycleOwner import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.shop_tile.view.* -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import okhttp3.ResponseBody -import org.hackillinois.android.App import org.hackillinois.android.R import org.hackillinois.android.database.entity.ShopItem -import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.launch -class ShopAdapter(private var itemList: List, private val buyItemListener : OnBuyItemListener) : +class ShopAdapter(private var itemList: List, private val buyItemListener: OnBuyItemListener) : RecyclerView.Adapter() { private lateinit var context: Context inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) @@ -69,43 +61,9 @@ class ShopAdapter(private var itemList: List, private val buyItemListe } val plusButton: ImageView = findViewById(R.id.plusButton) -// plusButton.setOnClickListener { -// Log.d("CartDebug", "Plus button clicked!") -// Log.d("Item ID: ", ""+item.itemId) -// App.getAPI().addItemCart(item.itemId).enqueue(object : Callback { -// override fun onResponse(call: Call, response: Response) { -// if (response.isSuccessful) { -// Log.d("CartDebug", "Item added to cart successfully!: ${response.code()}, ${response.message()}, ${response.body().toString()}") -// } else { -// Log.e("CartDebug", "Failed to add item: ${response.code()}") -// } -// } -// -// override fun onFailure(call: Call, t: Throwable) { -// Log.e("CartDebug", "Error adding item to cart", t) -// } -// }) -// } -// plusButton.setOnClickListener { -// Log.d("CartDebug", "Plus button clicked!") -// Log.d("Item ID: ", ""+item.itemId) -// itemView.findViewTreeLifecycleOwner()?.lifecycleScope?.launch { -// try { -// val response = App.getAPI().addItemCart(item.itemId) -// if (response.isSuccessful) { -// val cartResponse = response.body() -// Log.d("CartDebug", "Item added: $cartResponse") -// } else { -// Log.e("CartDebug", "Failed to add item: ${response.code()}") -// } -// } catch (e: Exception) { -// Log.e("CartDebug", "Error adding item to cart", e) -// } -// } ?: Log.e("CartDebug", "No LifecycleOwner found for itemView") -// } plusButton.setOnClickListener { Log.d("CartDebug", "Plus button clicked!") - Log.d("Item ID: ", ""+item.itemId) + Log.d("Item ID: ", "" + item.itemId) buyItemListener.onBuyItem(item) } } @@ -117,6 +75,6 @@ class ShopAdapter(private var itemList: List, private val buyItemListe } interface OnBuyItemListener { - fun onBuyItem(item : ShopItem) + fun onBuyItem(item: ShopItem) } } From a872c2f0209ca830e8e610b15c423d0f7ac5eee4 Mon Sep 17 00:00:00 2001 From: sneh-saraff Date: Sun, 16 Feb 2025 12:34:47 -0600 Subject: [PATCH 13/20] implemented get cart api --- .../android/view/shop/CartFragment.kt | 38 ++++++++++++++++--- .../res/layout/fragment_point_shop_cart.xml | 4 +- .../main/res/layout/point_shop_cart_tile.xml | 4 +- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt index 6a6a1e4b..6917fbf0 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt @@ -1,13 +1,18 @@ package org.hackillinois.android.view.shop import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.launch +import org.hackillinois.android.App import org.hackillinois.android.R +import org.hackillinois.android.database.entity.Cart import org.hackillinois.android.database.entity.ShopItem class CartFragment : Fragment() { @@ -51,11 +56,32 @@ class CartFragment : Fragment() { } private fun fetchCartData() { - // random example to see the layout - cartItems = listOf( - Pair(ShopItem("1", "T-Shirt", 10, false, 1, "https://example.com/tshirt.png"), 2), - Pair(ShopItem("2", "Sticker", 5, false, 1, "https://example.com/sticker.png"), 3) - ) - cartAdapter.updateCart(cartItems) + lifecycleScope.launch { + try { + // First, get all available shop items + val shopItems: List = App.getAPI().shop() + + // Next, get the cart from the API + val cart: Cart = App.getAPI().getCart() + val items = mutableListOf>() + + // Iterate over the map of itemId -> quantity from the cart. + for ((itemId, quantity) in cart.items) { + // Look up the ShopItem from the shopItems list using itemId + val shopItem = shopItems.find { it.itemId == itemId } + if (shopItem != null) { + items.add(Pair(shopItem, quantity)) + } else { + Log.e("CartFragment", "ShopItem not found for itemId: $itemId") + } + } + cartItems = items + cartAdapter.updateCart(cartItems) + } catch (e: Exception) { + Log.e("CartFragment", "Error fetching cart items", e) + } + } } + + } diff --git a/app/src/main/res/layout/fragment_point_shop_cart.xml b/app/src/main/res/layout/fragment_point_shop_cart.xml index 38c0f32a..5031a0db 100644 --- a/app/src/main/res/layout/fragment_point_shop_cart.xml +++ b/app/src/main/res/layout/fragment_point_shop_cart.xml @@ -118,13 +118,13 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" app:spanCount="2" - app:layout_constraintVertical_bias="0.1" + app:layout_constraintVertical_bias="0.0" app:layout_constraintHorizontal_bias="0.5" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layout_constraintBottom_toTopOf="@id/redeemButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/title_textview_cart" /> + app:layout_constraintTop_toBottomOf="@id/backButton" /> diff --git a/app/src/main/res/layout/point_shop_cart_tile.xml b/app/src/main/res/layout/point_shop_cart_tile.xml index efbd0ee3..a3e01295 100644 --- a/app/src/main/res/layout/point_shop_cart_tile.xml +++ b/app/src/main/res/layout/point_shop_cart_tile.xml @@ -37,8 +37,10 @@ Date: Sun, 16 Feb 2025 18:49:43 -0600 Subject: [PATCH 14/20] plus button in cart and splitting the view for the first 2 items --- .../android/view/shop/CartAdapter.kt | 25 +++++-- .../android/view/shop/CartFragment.kt | 21 +++++- .../android/view/shop/ShopFragment.kt | 69 +++++++++++++++---- .../main/res/layout/fragment_point_shop.xml | 46 ++++++++++--- 4 files changed, 131 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt index 92005f47..86d7458a 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt @@ -1,6 +1,7 @@ package org.hackillinois.android.view.shop import android.content.Context +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -10,8 +11,9 @@ import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import org.hackillinois.android.R import org.hackillinois.android.database.entity.ShopItem +import org.hackillinois.android.view.shop.ShopAdapter.OnBuyItemListener -class CartAdapter(private var cartItems: List>) : +class CartAdapter(private var cartItems: List>, private val buyItemListener: OnBuyItemListener) : RecyclerView.Adapter() { private lateinit var context: Context @@ -19,7 +21,8 @@ class CartAdapter(private var cartItems: List>) : inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val view = LayoutInflater.from(parent.context).inflate(R.layout.point_shop_cart_tile, parent, false) + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.point_shop_cart_tile, parent, false) context = parent.context return ViewHolder(view) } @@ -40,11 +43,15 @@ class CartAdapter(private var cartItems: List>) : val shopItemImageView: ImageView = findViewById(R.id.image_view_sticker_symbol) Glide.with(context).load(item.imageURL).into(shopItemImageView) -// -// val plusButton: ImageView = findViewById(R.id.button_plus) -// plusButton.setOnClickListener { -// // Logic to increase quantity in the cart -// } + + val plusButton: TextView = findViewById(R.id.button_plus) + + plusButton.setOnClickListener { + Log.d("CartDebug", "Plus button clicked!") + Log.d("Item ID: ", "" + item.itemId) + buyItemListener.onBuyItem(item) + } + } } @@ -52,4 +59,8 @@ class CartAdapter(private var cartItems: List>) : this.cartItems = newCartItems notifyDataSetChanged() } + + interface OnBuyItemListener { + fun onBuyItem(item: ShopItem) + } } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt index 6917fbf0..1ed4983a 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt @@ -15,7 +15,7 @@ import org.hackillinois.android.R import org.hackillinois.android.database.entity.Cart import org.hackillinois.android.database.entity.ShopItem -class CartFragment : Fragment() { +class CartFragment : Fragment(), CartAdapter.OnBuyItemListener { private lateinit var recyclerView: RecyclerView private lateinit var cartAdapter: CartAdapter @@ -31,7 +31,7 @@ class CartFragment : Fragment() { recyclerView = view.findViewById(R.id.recyclerview_point_shop) recyclerView.layoutManager = GridLayoutManager(context, 2) - cartAdapter = CartAdapter(cartItems) + cartAdapter = CartAdapter(cartItems, this) recyclerView.adapter = cartAdapter fetchCartData() @@ -83,5 +83,22 @@ class CartFragment : Fragment() { } } + override fun onBuyItem(item: ShopItem) { + lifecycleScope.launch { + try { + val response = App.getAPI().addItemCart(item.itemId) + if (response.isSuccessful) { + // Update UI or local data with the new cart state + fetchCartData() + Log.d("CartDebug", "Item added: ${response.body()}") + } else { + Log.e("CartDebug", "Failed to add item: ${response.code()}") + } + } catch (e: Exception) { + Log.e("CartDebug", "Error adding item to cart", e) + } + } + } + } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index 77b30e34..c93fba62 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -15,8 +15,11 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.fragment_point_shop.number_of_coins_textview import kotlinx.android.synthetic.main.fragment_point_shop.view.recyclerview_point_shop +import kotlinx.android.synthetic.main.shop_tile.view.priceTextView +import kotlinx.android.synthetic.main.shop_tile.view.quantityTextView import kotlinx.coroutines.launch import org.hackillinois.android.App import org.hackillinois.android.R @@ -37,6 +40,15 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { private lateinit var mLayoutManager: LinearLayoutManager private lateinit var mAdapter: ShopAdapter + private lateinit var sticker1ImageView: ImageView + private lateinit var sticker2ImageView: ImageView + private lateinit var sticker1TextView: TextView + private lateinit var sticker2TextView: TextView + private lateinit var priceTextView1: TextView + private lateinit var priceTextView2: TextView + private lateinit var quantityTextView1: TextView + private lateinit var quantityTextView2: TextView + private lateinit var merchButton: TextView private lateinit var raffleButton: TextView @@ -76,22 +88,29 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { ): View? { val view = inflater.inflate(R.layout.fragment_point_shop, container, false) + sticker1ImageView = view.findViewById(R.id.image_view_sticker1_symbol) + sticker2ImageView = view.findViewById(R.id.image_view_sticker2_symbol) + sticker1TextView = view.findViewById(R.id.text_view_sticker1) + sticker2TextView = view.findViewById(R.id.text_view_sticker2) + priceTextView1 = view.findViewById(R.id.priceTextView1) + priceTextView2 = view.findViewById(R.id.priceTextView2) + quantityTextView1 = view.findViewById(R.id.quantityTextView1) + quantityTextView2 = view.findViewById(R.id.quantityTextView2) + merchButton = view.findViewById(R.id.merchButton) raffleButton = view.findViewById(R.id.raffleButton) - mAdapter = ShopAdapter(shop, this) + recyclerView = view.recyclerview_point_shop + - recyclerView = view.recyclerview_point_shop.apply { - mLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - this.layoutManager = mLayoutManager - this.adapter = mAdapter - } shopViewModel.shopLiveData.observe( viewLifecycleOwner, - Observer { - // will split shop items into Merch or Raffle category - updateShopItems(it) + Observer { shopItems -> + // Split the shop items into Merch or Raffle category + updateShopItems(shopItems) + updateShopUI() + }, ) @@ -134,15 +153,38 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { // Split the shop items into Merch and Raffle items merchItems = newShop.filter { !it.isRaffle } raffleItems = newShop.filter { it.isRaffle } - - // Update the UI based on the selected button - updateShopUI() } + private fun updateShopUI() { // if showingMerch variable is True based on selected button, show merch items. else, show raffle val itemsToShow = if (showingMerch) merchItems else raffleItems - mAdapter.updateShop(itemsToShow) + val recyclerViewItems = + if (itemsToShow.size > 2) itemsToShow.subList(2, itemsToShow.size) else listOf() + + recyclerView.apply { + mLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + this.layoutManager = mLayoutManager + mAdapter = ShopAdapter(recyclerViewItems, this@ShopFragment) + this.adapter = mAdapter + } + // Update the stickers with the first two items + if (itemsToShow.isNotEmpty()) { + val firstItem = itemsToShow[0] + Glide.with(requireContext()).load(firstItem.imageURL).into(sticker1ImageView) + sticker1TextView.text = firstItem.name + priceTextView1.text = firstItem.price.toString() + quantityTextView1.text = if (firstItem.isRaffle) resources.getString(R.string.unlimited) else resources.getString(R.string.shopquantity, firstItem.quantity) + } + + if (itemsToShow.size >= 2) { + val secondItem = itemsToShow[1] + Glide.with(requireContext()).load(secondItem.imageURL).into(sticker2ImageView) + sticker2TextView.text = secondItem.name + priceTextView2.text = secondItem.price.toString() + quantityTextView2.text = if (secondItem.isRaffle) resources.getString(R.string.unlimited) else resources.getString(R.string.shopquantity, secondItem.quantity) + } + } // update merch ViewModel on click @@ -207,6 +249,7 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { .getString("provider", "") ?: "" == "github" } + override fun onBuyItem(item: ShopItem) { // Implement your buying logic here (e.g., make a network call) lifecycleScope.launch { diff --git a/app/src/main/res/layout/fragment_point_shop.xml b/app/src/main/res/layout/fragment_point_shop.xml index 7cbae687..03651bb8 100644 --- a/app/src/main/res/layout/fragment_point_shop.xml +++ b/app/src/main/res/layout/fragment_point_shop.xml @@ -126,8 +126,8 @@ + + + + Date: Sun, 16 Feb 2025 18:56:00 -0600 Subject: [PATCH 15/20] fixed lint issues --- .../org/hackillinois/android/view/shop/CartAdapter.kt | 1 - .../org/hackillinois/android/view/shop/CartFragment.kt | 2 -- .../org/hackillinois/android/view/shop/ShopAdapter.kt | 2 -- .../org/hackillinois/android/view/shop/ShopFragment.kt | 9 --------- 4 files changed, 14 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt index 86d7458a..a25dc0a7 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt @@ -51,7 +51,6 @@ class CartAdapter(private var cartItems: List>, private val Log.d("Item ID: ", "" + item.itemId) buyItemListener.onBuyItem(item) } - } } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt index 1ed4983a..a287645c 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt @@ -99,6 +99,4 @@ class CartFragment : Fragment(), CartAdapter.OnBuyItemListener { } } } - - } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 085b6350..94f5dcb4 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -18,8 +18,6 @@ class ShopAdapter(private var itemList: List, private val buyItemListe private lateinit var context: Context inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) - - // onCreateViewHolder used to display scrollable list of items // implemented as part of RecyclerView's adapter, responsible for creating new ViewHolder objects override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index c93fba62..995aa41b 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -18,8 +18,6 @@ import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.fragment_point_shop.number_of_coins_textview import kotlinx.android.synthetic.main.fragment_point_shop.view.recyclerview_point_shop -import kotlinx.android.synthetic.main.shop_tile.view.priceTextView -import kotlinx.android.synthetic.main.shop_tile.view.quantityTextView import kotlinx.coroutines.launch import org.hackillinois.android.App import org.hackillinois.android.R @@ -35,7 +33,6 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { } private lateinit var shopViewModel: ShopViewModel - private var shop: List = listOf() private lateinit var recyclerView: RecyclerView private lateinit var mLayoutManager: LinearLayoutManager private lateinit var mAdapter: ShopAdapter @@ -102,15 +99,12 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { recyclerView = view.recyclerview_point_shop - - shopViewModel.shopLiveData.observe( viewLifecycleOwner, Observer { shopItems -> // Split the shop items into Merch or Raffle category updateShopItems(shopItems) updateShopUI() - }, ) @@ -155,7 +149,6 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { raffleItems = newShop.filter { it.isRaffle } } - private fun updateShopUI() { // if showingMerch variable is True based on selected button, show merch items. else, show raffle val itemsToShow = if (showingMerch) merchItems else raffleItems @@ -184,7 +177,6 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { priceTextView2.text = secondItem.price.toString() quantityTextView2.text = if (secondItem.isRaffle) resources.getString(R.string.unlimited) else resources.getString(R.string.shopquantity, secondItem.quantity) } - } // update merch ViewModel on click @@ -249,7 +241,6 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { .getString("provider", "") ?: "" == "github" } - override fun onBuyItem(item: ShopItem) { // Implement your buying logic here (e.g., make a network call) lifecycleScope.launch { From 8874184cf199adc9298ae5592e4f2b53f5f00145 Mon Sep 17 00:00:00 2001 From: Aditya Kshirsagar Date: Mon, 17 Feb 2025 18:53:30 -0600 Subject: [PATCH 16/20] fixed point shop tile spacing, along with adding popups for succesful/failed additions --- .../android/view/shop/ShopAdapter.kt | 2 + .../android/view/shop/ShopFragment.kt | 36 +++++++++++++++ .../main/res/layout/fragment_point_shop.xml | 45 ++++++++++--------- .../res/layout/fragment_point_shop_cart.xml | 2 +- .../main/res/layout/point_shop_cart_tile.xml | 9 ++-- app/src/main/res/layout/point_shop_tile.xml | 13 +++--- 6 files changed, 74 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 94f5dcb4..9e0b0cea 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -18,6 +18,7 @@ class ShopAdapter(private var itemList: List, private val buyItemListe private lateinit var context: Context inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) + // onCreateViewHolder used to display scrollable list of items // implemented as part of RecyclerView's adapter, responsible for creating new ViewHolder objects override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { @@ -38,6 +39,7 @@ class ShopAdapter(private var itemList: List, private val buyItemListe bind(item, holder.itemView, position + 1) } + private fun bind(item: ShopItem, itemView: View, position: Int) { itemView.apply { val textViewSticker: TextView = findViewById(R.id.text_view_sticker) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index 995aa41b..91b1319c 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import android.widget.Toast import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.Observer @@ -55,6 +56,9 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { // Merch tab is default selected private var showingMerch: Boolean = true + private lateinit var miniTile1: View + private lateinit var miniTile2: View + override fun onPause() { super.onPause() shopViewModel.stopTimer() @@ -63,6 +67,7 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { override fun onResume() { super.onResume() shopViewModel.startTimer() + updateShopUI() } override fun onCreate(savedInstanceState: Bundle?) { @@ -99,6 +104,11 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { recyclerView = view.recyclerview_point_shop + val plusButton1: ImageView = view.findViewById(R.id.plusButton1) + val plusButton2: ImageView = view.findViewById(R.id.plusButton2) +// miniTile1 = view.findViewById(R.id.mini_tile_1) +// miniTile2 = view.findViewById(R.id.mini_tile_2) + shopViewModel.shopLiveData.observe( viewLifecycleOwner, Observer { shopItems -> @@ -139,9 +149,15 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { transaction.addToBackStack(null) // Optional, for back navigation transaction.commit() } + + plusButton1.setOnClickListener { buyFirstItem() } + plusButton2.setOnClickListener { buySecondItem() } + + return view } + // Called in onCreateView within shopLiveData.observe private fun updateShopItems(newShop: List) { // Split the shop items into Merch and Raffle items @@ -249,12 +265,32 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { 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 itme: ${response.code()}", Toast.LENGTH_SHORT).show() } } 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() } + updateShopUI() + } + } + + private fun buyFirstItem() { + if (merchItems.isNotEmpty()) { + val firstItem = merchItems[0] + Log.d("ShopFragment", "Buying: ${firstItem.name}") + onBuyItem(firstItem) + } + } + + private fun buySecondItem() { + if (merchItems.size >= 2) { + val secondItem = merchItems[1] + Log.d("ShopFragment", "Buying: ${secondItem.name}") + onBuyItem(secondItem) } } } diff --git a/app/src/main/res/layout/fragment_point_shop.xml b/app/src/main/res/layout/fragment_point_shop.xml index 03651bb8..f0a2a63b 100644 --- a/app/src/main/res/layout/fragment_point_shop.xml +++ b/app/src/main/res/layout/fragment_point_shop.xml @@ -37,20 +37,20 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/point_shop_cart_symbol" - android:text="@string/cart" - android:textColor="@color/magenta" android:fontFamily="@font/montserrat_bold" android:gravity="center" - android:textSize="14sp" android:paddingBottom="2.5dp" + android:text="@string/cart" + android:textColor="@color/magenta" + android:textSize="14sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.45" + app:layout_constraintHorizontal_bias="0.458" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.44" /> + app:layout_constraintVertical_bias="0.463" /> - + + app:layout_constraintVertical_bias="0.125" /> + app:layout_constraintVertical_bias="0.125" /> + app:layout_constraintVertical_bias="0.319" /> + app:layout_constraintVertical_bias="0.327" /> + android:layout_height="wrap_content" + android:layout_margin="5dp" > @@ -45,6 +42,8 @@ android:text="@string/sticker" android:textSize="16sp" android:textColor="@color/white" + android:layout_marginEnd="5dp" + android:layout_marginStart="5dp" app:layout_constraintBottom_toBottomOf="@id/image_view_sticker" app:layout_constraintEnd_toEndOf="@id/image_view_sticker" app:layout_constraintStart_toStartOf="@id/image_view_sticker" diff --git a/app/src/main/res/layout/point_shop_tile.xml b/app/src/main/res/layout/point_shop_tile.xml index f7358da0..db123567 100644 --- a/app/src/main/res/layout/point_shop_tile.xml +++ b/app/src/main/res/layout/point_shop_tile.xml @@ -50,18 +50,19 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:fontFamily="@font/montserrat_medium" + android:gravity="center" + android:scrollHorizontally="false" android:text="@string/sticker" - android:textSize="16sp" android:textColor="@color/white" + android:textSize="14sp" + android:layout_marginEnd="5dp" + android:layout_marginStart="5dp" app:layout_constraintBottom_toBottomOf="@id/image_view_sticker" app:layout_constraintEnd_toEndOf="@id/image_view_sticker" + app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="@id/image_view_sticker" app:layout_constraintTop_toTopOf="@id/image_view_sticker" - app:layout_constraintVertical_bias="0.125" - app:layout_constraintHorizontal_bias="0.5" - android:gravity="center" - android:scrollHorizontally="false" - /> + app:layout_constraintVertical_bias="0.125" /> Date: Mon, 17 Feb 2025 20:20:35 -0600 Subject: [PATCH 17/20] added Point Shop QR Code and cart functionality --- app/build.gradle | 3 + .../main/java/org/hackillinois/android/API.kt | 3 + .../android/database/entity/QRResponse.kt | 2 +- .../android/view/shop/CartAdapter.kt | 70 ++++++++---- .../android/view/shop/CartFragment.kt | 42 +++++--- .../android/view/shop/RedeemFragment.kt | 74 ++++++++++++- .../android/view/shop/ShopAdapter.kt | 2 +- .../android/view/shop/ShopFragment.kt | 100 +++++++++++++----- .../android/viewmodel/RedeemViewModel.kt | 72 +++++++++++++ .../main/res/layout/point_shop_cart_tile.xml | 26 +++-- app/src/main/res/values/strings.xml | 1 + 11 files changed, 323 insertions(+), 72 deletions(-) create mode 100644 app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt diff --git a/app/build.gradle b/app/build.gradle index a860c9b2..d8c7bad4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -129,6 +129,9 @@ dependencies { // Swipe-to-refresh implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + + //Json Parsing + implementation 'com.google.code.gson:gson:2.8.9' } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/org/hackillinois/android/API.kt b/app/src/main/java/org/hackillinois/android/API.kt index 0e4278fe..e4a606e1 100644 --- a/app/src/main/java/org/hackillinois/android/API.kt +++ b/app/src/main/java/org/hackillinois/android/API.kt @@ -79,6 +79,9 @@ interface API { @GET("shop/cart/qr/") suspend fun getCartQRCode(): QRResponse + @DELETE("shop/cart/{itemId}") + suspend fun removeItemCart(@Path("itemId") itemId: String): Response + // STAFF @POST("staff/attendance/") diff --git a/app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt b/app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt index f60a8700..553c7daa 100644 --- a/app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt +++ b/app/src/main/java/org/hackillinois/android/database/entity/QRResponse.kt @@ -1,3 +1,3 @@ package org.hackillinois.android.database.entity -data class QRResponse(val qrCode: String) +data class QRResponse(val QRCode: String) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt index a25dc0a7..336b5bf5 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt @@ -1,8 +1,10 @@ package org.hackillinois.android.view.shop import android.content.Context +import android.graphics.Rect import android.util.Log import android.view.LayoutInflater +import android.view.TouchDelegate import android.view.View import android.view.ViewGroup import android.widget.ImageView @@ -11,14 +13,37 @@ import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import org.hackillinois.android.R import org.hackillinois.android.database.entity.ShopItem -import org.hackillinois.android.view.shop.ShopAdapter.OnBuyItemListener -class CartAdapter(private var cartItems: List>, private val buyItemListener: OnBuyItemListener) : - RecyclerView.Adapter() { +class CartAdapter( + private var cartItems: List>, + private val listener: OnQuantityChangeListener +) : RecyclerView.Adapter() { private lateinit var context: Context - inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) + inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val textViewSticker: TextView = view.findViewById(R.id.text_view_sticker) + val quantityTextView: TextView = view.findViewById(R.id.number_text) + val shopItemImageView: ImageView = view.findViewById(R.id.image_view_sticker_symbol) + val plusButton: TextView = view.findViewById(R.id.button_plus) + val minusButton: TextView = view.findViewById(R.id.button_minus) + } + + private fun expandTouchArea(targetView: View, extraPadding: Int) { + val parentView = targetView.parent as? ViewGroup ?: return + parentView.post { + val rect = Rect() + targetView.getHitRect(rect) + rect.top -= extraPadding + rect.left -= extraPadding + rect.bottom += extraPadding + rect.right += extraPadding + + // Ensure we do not override existing touch delegates + parentView.touchDelegate = TouchDelegate(rect, targetView) + parentView.requestLayout() // Refresh layout so it applies + } + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) @@ -31,27 +56,25 @@ class CartAdapter(private var cartItems: List>, private val override fun onBindViewHolder(holder: ViewHolder, position: Int) { val (item, quantity) = cartItems[position] - bind(item, quantity, holder.itemView) - } - - private fun bind(item: ShopItem, quantity: Int, itemView: View) { - itemView.apply { - val textViewSticker: TextView = findViewById(R.id.text_view_sticker) - textViewSticker.text = item.name - val quantiyTextView: TextView = findViewById(R.id.number_text) - quantiyTextView.text = quantity.toString() + holder.textViewSticker.text = item.name + holder.quantityTextView.text = quantity.toString() + Glide.with(context).load(item.imageURL).into(holder.shopItemImageView) - val shopItemImageView: ImageView = findViewById(R.id.image_view_sticker_symbol) - Glide.with(context).load(item.imageURL).into(shopItemImageView) + // Increase quantity using plus button + holder.plusButton.setOnClickListener { + val newQuantity = quantity + 1 + listener.onIncreaseQuantity(item, newQuantity) + } - val plusButton: TextView = findViewById(R.id.button_plus) + expandTouchArea(holder.plusButton, 100) - plusButton.setOnClickListener { - Log.d("CartDebug", "Plus button clicked!") - Log.d("Item ID: ", "" + item.itemId) - buyItemListener.onBuyItem(item) - } + // Decrease quantity using minus button (allowing 0) + holder.minusButton.setOnClickListener { + val newQuantity = quantity - 1 + listener.onDecreaseQuantity(item, newQuantity) } + + expandTouchArea(holder.minusButton, 100) } fun updateCart(newCartItems: List>) { @@ -59,7 +82,8 @@ class CartAdapter(private var cartItems: List>, private val notifyDataSetChanged() } - interface OnBuyItemListener { - fun onBuyItem(item: ShopItem) + interface OnQuantityChangeListener { + fun onIncreaseQuantity(item: ShopItem, newQuantity: Int) + fun onDecreaseQuantity(item: ShopItem, newQuantity: Int) } } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt index a287645c..4be20170 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartFragment.kt @@ -15,7 +15,7 @@ import org.hackillinois.android.R import org.hackillinois.android.database.entity.Cart import org.hackillinois.android.database.entity.ShopItem -class CartFragment : Fragment(), CartAdapter.OnBuyItemListener { +class CartFragment : Fragment(), CartAdapter.OnQuantityChangeListener { private lateinit var recyclerView: RecyclerView private lateinit var cartAdapter: CartAdapter @@ -39,16 +39,15 @@ class CartFragment : Fragment(), CartAdapter.OnBuyItemListener { val backButton: View = view.findViewById(R.id.backButton) backButton.bringToFront() backButton.setOnClickListener { - requireActivity().supportFragmentManager.popBackStack() // Go back to the previous fragment + requireActivity().supportFragmentManager.popBackStack() // Go back to previous fragment } - // Handle Redeem Button Click val redeemButton: View = view.findViewById(R.id.redeemButton) redeemButton.setOnClickListener { val redeemFragment = RedeemFragment() requireActivity().supportFragmentManager.beginTransaction() .replace(R.id.contentFrame, redeemFragment) - .addToBackStack(null) // Allows back navigation + .addToBackStack(null) .commit() } @@ -58,16 +57,11 @@ class CartFragment : Fragment(), CartAdapter.OnBuyItemListener { private fun fetchCartData() { lifecycleScope.launch { try { - // First, get all available shop items val shopItems: List = App.getAPI().shop() - - // Next, get the cart from the API val cart: Cart = App.getAPI().getCart() val items = mutableListOf>() - // Iterate over the map of itemId -> quantity from the cart. for ((itemId, quantity) in cart.items) { - // Look up the ShopItem from the shopItems list using itemId val shopItem = shopItems.find { it.itemId == itemId } if (shopItem != null) { items.add(Pair(shopItem, quantity)) @@ -83,14 +77,13 @@ class CartFragment : Fragment(), CartAdapter.OnBuyItemListener { } } - override fun onBuyItem(item: ShopItem) { + override fun onIncreaseQuantity(item: ShopItem, newQuantity: Int) { lifecycleScope.launch { try { val response = App.getAPI().addItemCart(item.itemId) if (response.isSuccessful) { - // Update UI or local data with the new cart state - fetchCartData() Log.d("CartDebug", "Item added: ${response.body()}") + fetchCartData() // Refresh cart } else { Log.e("CartDebug", "Failed to add item: ${response.code()}") } @@ -99,4 +92,29 @@ class CartFragment : Fragment(), CartAdapter.OnBuyItemListener { } } } + + override fun onDecreaseQuantity(item: ShopItem, newQuantity: Int) { + lifecycleScope.launch { + try { + val response = App.getAPI().removeItemCart(item.itemId) + if (response.isSuccessful) { + Log.d("CartDebug", "Item removed: ${response.body()}") + if (newQuantity == 0) { + // If quantity is zero, remove the item from UI + fetchCartData() + } else { + // Just update the UI without full fetch + cartItems = cartItems.map { + if (it.first.itemId == item.itemId) Pair(it.first, newQuantity) else it + } + cartAdapter.updateCart(cartItems) + } + } else { + Log.e("CartDebug", "Failed to remove item: ${response.code()}") + } + } catch (e: Exception) { + Log.e("CartDebug", "Error removing item from cart", e) + } + } + } } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt index 211a8318..7e420fa5 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt @@ -1,14 +1,30 @@ package org.hackillinois.android.view.shop +import RedeemViewModel +import android.graphics.Bitmap +import android.graphics.Color import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView +import android.widget.Toast import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.google.zxing.BarcodeFormat +import com.google.zxing.EncodeHintType +import com.google.zxing.MultiFormatWriter +import com.google.zxing.WriterException import org.hackillinois.android.R +import java.util.EnumMap class RedeemFragment : Fragment() { + private lateinit var qrCodeImage: ImageView + private lateinit var redeemViewModel: RedeemViewModel + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -22,6 +38,62 @@ class RedeemFragment : Fragment() { backButton.setOnClickListener { requireActivity().supportFragmentManager.popBackStack() // Go back to previous fragment } + + qrCodeImage = view.findViewById(R.id.qr_code_placeholder) + + // Initialize and observe the ViewModel + redeemViewModel = ViewModelProvider(this).get(RedeemViewModel::class.java) + redeemViewModel.qrCodeLiveData.observe(viewLifecycleOwner, Observer { qrString -> + Log.d("RedeemFragment", "Updated QR Code: $qrString") + updateQRView(qrString) + }) + + redeemViewModel.errorLiveData.observe(viewLifecycleOwner) { errorMessage -> + Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show() + } + return view } -} + + private fun updateQRView(qrString: String) { + if (qrCodeImage.width > 0 && qrCodeImage.height > 0) { + Log.d("RedeemFragment", "Generating QR with text: $qrString") + val bitmap = generateQR(qrString) + qrCodeImage.setImageBitmap(bitmap) + } + } + + private fun generateQR(text: String): Bitmap { + val width = qrCodeImage.width + val height = qrCodeImage.height + + val pixels = IntArray(width * height) + val multiFormatWriter = MultiFormatWriter() + val hints = EnumMap(EncodeHintType::class.java) + hints[EncodeHintType.MARGIN] = 0 + + try { + val bitMatrix = multiFormatWriter.encode(text, BarcodeFormat.QR_CODE, width, height, hints) + val clear = Color.TRANSPARENT + val solid = Color.BLACK + for (x in 0 until width) { + for (y in 0 until height) { + pixels[y * width + x] = if (bitMatrix.get(x, y)) solid else clear + } + } + } catch (e: WriterException) { + e.printStackTrace() + } + return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888) + } + + override fun onResume() { + super.onResume() + redeemViewModel.startAutoRefresh() // Resume QR refresh when fragment is visible + } + + override fun onPause() { + super.onPause() + redeemViewModel.stopAutoRefresh() // Pause QR refresh when fragment is hidden + } +} \ No newline at end of file diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 9e0b0cea..28901b52 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -70,7 +70,7 @@ class ShopAdapter(private var itemList: List, private val buyItemListe } fun updateShop(shopItem: List) { - this.itemList = shopItem + this.itemList = shopItem.sortedBy { it.quantity == 0 } // Move out-of-stock items to the end notifyDataSetChanged() } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index 91b1319c..4b46f903 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -67,7 +67,7 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { override fun onResume() { super.onResume() shopViewModel.startTimer() - updateShopUI() +// updateShopUI() } override fun onCreate(savedInstanceState: Bundle?) { @@ -113,8 +113,8 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { viewLifecycleOwner, Observer { shopItems -> // Split the shop items into Merch or Raffle category - updateShopItems(shopItems) updateShopUI() + updateShopItems(shopItems) }, ) @@ -160,41 +160,91 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { // Called in onCreateView within shopLiveData.observe private fun updateShopItems(newShop: List) { - // Split the shop items into Merch and Raffle items - merchItems = newShop.filter { !it.isRaffle } - raffleItems = newShop.filter { it.isRaffle } + // Split shop items into categories + merchItems = newShop.filter { !it.isRaffle }.sortedBy { it.quantity == 0 } + raffleItems = newShop.filter { it.isRaffle }.sortedBy { it.quantity == 0 } + + // **Update only the RecyclerView items** + val recyclerViewItems = if (showingMerch) { + if (merchItems.size > 2) merchItems.subList(2, merchItems.size) else listOf() + } else { + raffleItems + } + + // Update adapter + mAdapter.updateShop(recyclerViewItems) } + + private fun updateShopUI() { - // if showingMerch variable is True based on selected button, show merch items. else, show raffle - val itemsToShow = if (showingMerch) merchItems else raffleItems + // Sort items so that out-of-stock items are pushed to the end + val sortedItems = if (showingMerch) { + merchItems.sortedBy { it.quantity == 0 } + } else { + raffleItems.sortedBy { it.quantity == 0 } + } + + // Ensure first two items are always displayed in the fixed sticker views + if (sortedItems.isNotEmpty()) { + val firstItem = sortedItems[0] + updateStickerView(firstItem, sticker1ImageView, sticker1TextView, priceTextView1, quantityTextView1) + } else { + clearStickerView(sticker1ImageView, sticker1TextView, priceTextView1, quantityTextView1) + } + + if (sortedItems.size >= 2) { + val secondItem = sortedItems[1] + updateStickerView(secondItem, sticker2ImageView, sticker2TextView, priceTextView2, quantityTextView2) + } else { + clearStickerView(sticker2ImageView, sticker2TextView, priceTextView2, quantityTextView2) + } + + // RecyclerView should only show items *after* the first two val recyclerViewItems = - if (itemsToShow.size > 2) itemsToShow.subList(2, itemsToShow.size) else listOf() + if (sortedItems.size > 2) sortedItems.subList(2, sortedItems.size) else listOf() recyclerView.apply { mLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - this.layoutManager = mLayoutManager + layoutManager = mLayoutManager mAdapter = ShopAdapter(recyclerViewItems, this@ShopFragment) - this.adapter = mAdapter - } - // Update the stickers with the first two items - if (itemsToShow.isNotEmpty()) { - val firstItem = itemsToShow[0] - Glide.with(requireContext()).load(firstItem.imageURL).into(sticker1ImageView) - sticker1TextView.text = firstItem.name - priceTextView1.text = firstItem.price.toString() - quantityTextView1.text = if (firstItem.isRaffle) resources.getString(R.string.unlimited) else resources.getString(R.string.shopquantity, firstItem.quantity) + adapter = mAdapter } + } - if (itemsToShow.size >= 2) { - val secondItem = itemsToShow[1] - Glide.with(requireContext()).load(secondItem.imageURL).into(sticker2ImageView) - sticker2TextView.text = secondItem.name - priceTextView2.text = secondItem.price.toString() - quantityTextView2.text = if (secondItem.isRaffle) resources.getString(R.string.unlimited) else resources.getString(R.string.shopquantity, secondItem.quantity) + // Helper function to update a sticker view + private fun updateStickerView( + item: ShopItem, + imageView: ImageView, + textView: TextView, + priceView: TextView, + quantityView: TextView + ) { + Glide.with(requireContext()).load(item.imageURL).into(imageView) + textView.text = item.name + priceView.text = item.price.toString() + quantityView.text = when { + item.isRaffle -> resources.getString(R.string.unlimited) + item.quantity == 0 -> resources.getString(R.string.out_of_stock) + else -> resources.getString(R.string.shopquantity, item.quantity) } } + // Helper function to clear sticker views if not enough items are available + private fun clearStickerView( + imageView: ImageView, + textView: TextView, + priceView: TextView, + quantityView: TextView + ) { + imageView.setImageDrawable(null) + textView.text = "" + priceView.text = "" + quantityView.text = "" + } + + + // update merch ViewModel on click private val merchClickListener = View.OnClickListener { if (!merchButton.isSelected) { @@ -268,7 +318,7 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { 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 itme: ${response.code()}", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), "Failed to add item: ${response.code()}", Toast.LENGTH_SHORT).show() } } catch (e: Exception) { Log.e("CartDebug", "Error adding item to cart", e) diff --git a/app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt b/app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt new file mode 100644 index 00000000..76989663 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt @@ -0,0 +1,72 @@ +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.* +import okhttp3.ResponseBody +import org.hackillinois.android.App +import org.hackillinois.android.database.entity.QRResponse +import retrofit2.HttpException +import com.google.gson.JsonParser + +class RedeemViewModel : ViewModel() { + + private val _qrCodeLiveData = MutableLiveData() + val qrCodeLiveData: LiveData = _qrCodeLiveData + + private val _errorLiveData = MutableLiveData() + val errorLiveData: LiveData = _errorLiveData + + private var refreshJob: Job? = null + + private fun fetchQRCode() { + viewModelScope.launch(Dispatchers.IO) { + try { + val response: QRResponse = App.getAPI().getCartQRCode() + val extractedQRCode = extractQRString(response.QRCode) + _qrCodeLiveData.postValue(extractedQRCode) + } catch (e: HttpException) { + val errorMessage = extractErrorMessage(e.response()?.errorBody()) + _errorLiveData.postValue("Error: $errorMessage") + } catch (e: Exception) { + e.printStackTrace() + _errorLiveData.postValue("Unexpected error: ${e.message}") + } + } + } + + private fun extractQRString(qrCodeUrl: String): String { + return qrCodeUrl.substringAfter("qr=", "Invalid QR Code") + } + + // Extract the error message from the response body + private fun extractErrorMessage(errorBody: ResponseBody?): String { + return try { + val jsonString = errorBody?.string() ?: return "Unknown error" + val jsonObject = JsonParser.parseString(jsonString).asJsonObject + jsonObject["message"]?.asString ?: "Unknown error" + } catch (e: Exception) { + "Failed to parse error response" + } + } + + fun startAutoRefresh() { + if (refreshJob?.isActive == true) return // Prevent duplicate jobs + + refreshJob = viewModelScope.launch { + while (isActive) { + fetchQRCode() + delay(15000) // Refresh every 15 seconds + } + } + } + + fun stopAutoRefresh() { + refreshJob?.cancel() // Stop refreshing when fragment is not visible + } + + override fun onCleared() { + super.onCleared() + stopAutoRefresh() + } +} diff --git a/app/src/main/res/layout/point_shop_cart_tile.xml b/app/src/main/res/layout/point_shop_cart_tile.xml index 55de5455..6dcdee13 100644 --- a/app/src/main/res/layout/point_shop_cart_tile.xml +++ b/app/src/main/res/layout/point_shop_cart_tile.xml @@ -2,9 +2,12 @@ + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="5dp" + android:clickable="false" + android:focusable="false" + android:elevation="0dp"> @@ -76,21 +79,25 @@ app:layout_constraintBottom_toBottomOf="@id/image_view_number_bar" /> + + + + app:layout_constraintVertical_bias="1.0" /> - 1 BACK SCAN HERE TO \nCOMPLETE PURCHASE + OUT OF STOCK From 7c03c47989daf7501136924c612dfd5478f906ad Mon Sep 17 00:00:00 2001 From: Aditya Kshirsagar Date: Mon, 17 Feb 2025 20:27:30 -0600 Subject: [PATCH 18/20] ktlint satisfaction --- .../hackillinois/android/view/shop/CartAdapter.kt | 2 -- .../android/view/shop/RedeemFragment.kt | 13 ++++++++----- .../hackillinois/android/view/shop/ShopAdapter.kt | 2 -- .../hackillinois/android/view/shop/ShopFragment.kt | 6 ------ .../android/viewmodel/RedeemViewModel.kt | 8 ++++++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt index 336b5bf5..f110f37b 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt @@ -2,7 +2,6 @@ package org.hackillinois.android.view.shop import android.content.Context import android.graphics.Rect -import android.util.Log import android.view.LayoutInflater import android.view.TouchDelegate import android.view.View @@ -39,7 +38,6 @@ class CartAdapter( rect.bottom += extraPadding rect.right += extraPadding - // Ensure we do not override existing touch delegates parentView.touchDelegate = TouchDelegate(rect, targetView) parentView.requestLayout() // Refresh layout so it applies } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt index 7e420fa5..a3baa0cb 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/RedeemFragment.kt @@ -43,10 +43,13 @@ class RedeemFragment : Fragment() { // Initialize and observe the ViewModel redeemViewModel = ViewModelProvider(this).get(RedeemViewModel::class.java) - redeemViewModel.qrCodeLiveData.observe(viewLifecycleOwner, Observer { qrString -> - Log.d("RedeemFragment", "Updated QR Code: $qrString") - updateQRView(qrString) - }) + redeemViewModel.qrCodeLiveData.observe( + viewLifecycleOwner, + Observer { qrString -> + Log.d("RedeemFragment", "Updated QR Code: $qrString") + updateQRView(qrString) + } + ) redeemViewModel.errorLiveData.observe(viewLifecycleOwner) { errorMessage -> Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show() @@ -96,4 +99,4 @@ class RedeemFragment : Fragment() { super.onPause() redeemViewModel.stopAutoRefresh() // Pause QR refresh when fragment is hidden } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt index 28901b52..8b4d5fc5 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -18,7 +18,6 @@ class ShopAdapter(private var itemList: List, private val buyItemListe private lateinit var context: Context inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) - // onCreateViewHolder used to display scrollable list of items // implemented as part of RecyclerView's adapter, responsible for creating new ViewHolder objects override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { @@ -39,7 +38,6 @@ class ShopAdapter(private var itemList: List, private val buyItemListe bind(item, holder.itemView, position + 1) } - private fun bind(item: ShopItem, itemView: View, position: Int) { itemView.apply { val textViewSticker: TextView = findViewById(R.id.text_view_sticker) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt index 4b46f903..3ba74770 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -153,11 +153,9 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { plusButton1.setOnClickListener { buyFirstItem() } plusButton2.setOnClickListener { buySecondItem() } - return view } - // Called in onCreateView within shopLiveData.observe private fun updateShopItems(newShop: List) { // Split shop items into categories @@ -175,8 +173,6 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { mAdapter.updateShop(recyclerViewItems) } - - private fun updateShopUI() { // Sort items so that out-of-stock items are pushed to the end val sortedItems = if (showingMerch) { @@ -243,8 +239,6 @@ class ShopFragment : Fragment(), ShopAdapter.OnBuyItemListener { quantityView.text = "" } - - // update merch ViewModel on click private val merchClickListener = View.OnClickListener { if (!merchButton.isSelected) { diff --git a/app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt b/app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt index 76989663..354389e1 100644 --- a/app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt +++ b/app/src/main/java/org/hackillinois/android/viewmodel/RedeemViewModel.kt @@ -2,12 +2,16 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.* +import com.google.gson.JsonParser +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import okhttp3.ResponseBody import org.hackillinois.android.App import org.hackillinois.android.database.entity.QRResponse import retrofit2.HttpException -import com.google.gson.JsonParser class RedeemViewModel : ViewModel() { From 5836a148a78004cd5094ba2cd1dad35d70e4f18b Mon Sep 17 00:00:00 2001 From: Aditya Kshirsagar Date: Mon, 17 Feb 2025 20:30:05 -0600 Subject: [PATCH 19/20] ktlint satisfaction --- .../main/java/org/hackillinois/android/view/shop/CartAdapter.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt index f110f37b..e15bb56e 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt @@ -37,7 +37,6 @@ class CartAdapter( rect.left -= extraPadding rect.bottom += extraPadding rect.right += extraPadding - parentView.touchDelegate = TouchDelegate(rect, targetView) parentView.requestLayout() // Refresh layout so it applies } From 3fd2b2319ebc565c977a48947cd0505869c018f2 Mon Sep 17 00:00:00 2001 From: Aditya Kshirsagar Date: Mon, 17 Feb 2025 20:33:30 -0600 Subject: [PATCH 20/20] ktlint satisfaction --- .../main/java/org/hackillinois/android/view/shop/CartAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt index e15bb56e..bb836948 100644 --- a/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt +++ b/app/src/main/java/org/hackillinois/android/view/shop/CartAdapter.kt @@ -38,7 +38,7 @@ class CartAdapter( rect.bottom += extraPadding rect.right += extraPadding parentView.touchDelegate = TouchDelegate(rect, targetView) - parentView.requestLayout() // Refresh layout so it applies + parentView.requestLayout() // Refresh layout so it applies } }