diff --git a/.gitignore b/.gitignore index e3ad875b4..e55e199ab 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ out/ .gradle/ build/ .idea/ +gradle/wrapper/ # Local configuration file (sdk path, etc) local.properties @@ -71,4 +72,4 @@ fastlane/readme.md # Crashlytics and API keys src/main/assets/crashlytics-build.properties src/main/res/values/com_crashlytics_export_strings.xml -crashlytics.properties \ No newline at end of file +crashlytics.properties diff --git a/PennMobile/build.gradle b/PennMobile/build.gradle index 89b22e0de..4a0982ece 100644 --- a/PennMobile/build.gradle +++ b/PennMobile/build.gradle @@ -6,7 +6,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.1' + classpath 'com.android.tools.build:gradle:4.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jacoco:org.jacoco.core:0.8.5" } @@ -35,11 +35,11 @@ android { } release {} } - compileSdkVersion 32 + compileSdkVersion 33 buildToolsVersion '29.0.3' defaultConfig { - minSdkVersion 18 - targetSdkVersion 32 + minSdkVersion 26 + targetSdkVersion 33 vectorDrawables.useSupportLibrary = true multiDexEnabled true buildConfigField ("String", "PLATFORM_REDIRECT_URI", getPlatformRedirectUri()) @@ -53,6 +53,9 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 + } } dependencies { @@ -62,7 +65,7 @@ dependencies { implementation 'androidx.multidex:multidex:2.0.1' implementation 'com.google.maps:google-maps-services:0.13.0' implementation 'org.jsoup:jsoup:1.13.1' - implementation 'com.google.android.material:material:1.1.0' + implementation 'com.google.android.material:material:1.6.0' implementation 'androidx.percentlayout:percentlayout:1.0.0' implementation 'androidx.exifinterface:exifinterface:1.2.0' implementation 'androidx.preference:preference-ktx:1.1.1' @@ -70,30 +73,32 @@ dependencies { implementation 'com.google.android.gms:play-services-location:17.0.0' implementation 'joda-time:joda-time:2.10.6' implementation 'org.apache.commons:commons-lang3:3.10' - implementation 'com.google.android.material:material:1.1.0' implementation 'com.jakewharton:butterknife:10.2.1' implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' + implementation ("androidx.lifecycle:lifecycle-extensions:2.2.0@aar") { + transitive = true + } annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1' implementation 'com.squareup.retrofit:retrofit:1.9.0' implementation 'com.squareup.picasso:picasso:2.71828' implementation 'com.squareup.okhttp:okhttp:2.7.5' implementation 'io.reactivex:rxandroid:1.2.1' implementation 'androidx.browser:browser:1.2.0' - implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.daimajia.swipelayout:library:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.13' androidTestImplementation 'org.testng:testng:7.1.0' - implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3' + implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' implementation 'androidx.cardview:cardview:1.0.0' implementation 'com.github.ahorn:android-rss:master-SNAPSHOT' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // official release is several years old and is not thread-safe implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" implementation 'com.eightbitlab:supportrenderscriptblur:1.0.2' - implementation 'com.eightbitlab:blurview:1.6.3' implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'com.github.searchy2:CustomAlertViewDialogue:2.6.1' implementation 'com.airbnb.android:lottie:4.2.0' @@ -104,6 +109,11 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'com.kaspersky.android-components:kaspresso:1.1.0' + implementation "com.squareup.retrofit2:retrofit:2.6.2" + implementation "com.squareup.retrofit2:converter-moshi:2.5.0" + implementation 'com.squareup.retrofit2:converter-scalars:2.5.0' + implementation 'com.squareup.retrofit2:converter-gson:2.5.0' + } String getPlatformClientID() { diff --git a/PennMobile/src/main/AndroidManifest.xml b/PennMobile/src/main/AndroidManifest.xml index e309e37f5..67481f37b 100644 --- a/PennMobile/src/main/AndroidManifest.xml +++ b/PennMobile/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="70" + android:versionName="3.0.0"> 20 && gif is AnimatedVectorDrawable) { + if (gif is AnimatedVectorDrawable) { gif.start() } else { Glide.with(this).asGif().load(R.drawable.logo_gif_transparent).listener(object : RequestListener { @@ -60,10 +54,9 @@ class AboutFragment : Fragment() { view.our_team_rv?.layoutManager = GridLayoutManager(context, 3) view.alumni_rv?.layoutManager = GridLayoutManager(context, 3) - val members = arrayListOf("Rohan Chhaya", "Anna Jiang", "Julius Snipes", - "Zhiyan Lu", "Belinda Xi","Vishesh Patel", "Ali Krema", "Jenny Li", "Sruthi Kurada") + val members = arrayListOf("Rohan Chhaya", "Julius Snipes", "Aaron Mei", "Trini Feng", "Vedha Avali") val alumni = arrayListOf("Marta GarcĂ­a Ferreiro", "Varun Ramakrishnan", "Sahit Penmatcha", - "Anna Wang", "Sophia Ye", "Awad Irfan", "Liz Powell", "Davies Lumumba") + "Anna Wang", "Sophia Ye", "Awad Irfan", "Liz Powell", "Davies Lumumba", "Anna Jiang", "Ali Krema") view.our_team_rv?.adapter = AboutAdapter(members) view.alumni_rv?.adapter = AboutAdapter(alumni) @@ -74,24 +67,17 @@ class AboutFragment : Fragment() { startActivity(i) } - view.feedback_btn?.setOnClickListener { - val link = Intent(Intent.ACTION_VIEW, Uri.parse("https://airtable.com/shr1oylDR3qzCpTXq")) - startActivity(link) - } - view.licenses_btn?.setOnClickListener { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val webView = LayoutInflater.from(mActivity).inflate(R.layout.dialog_licenses, null) as WebView - webView.loadUrl("file:///android_asset/open_source_licenses.html") - AlertDialog.Builder(mActivity, R.style.Theme_AppCompat_Light_Dialog_Alert) - .setTitle(getString(R.string.action_licenses)) - .setView(webView) - .setPositiveButton(android.R.string.ok, null) - .show() - } + val webView = LayoutInflater.from(mActivity).inflate(R.layout.dialog_licenses, null) as WebView + webView.loadUrl("file:///android_asset/open_source_licenses.html") + AlertDialog.Builder(mActivity, R.style.Theme_AppCompat_Light_Dialog_Alert) + .setTitle(getString(R.string.action_licenses)) + .setView(webView) + .setPositiveButton(android.R.string.ok, null) + .show() } - mActivity.toolbar.visibility = View.VISIBLE + //mActivity.toolbar.visibility = View.VISIBLE mActivity.hideBottomBar() mActivity.setTitle(R.string.contacts) @@ -103,9 +89,7 @@ class AboutFragment : Fragment() { val mActivity : MainActivity = activity as MainActivity mActivity.removeTabs() mActivity.setTitle(R.string.about) - if (Build.VERSION.SDK_INT > 17) { - mActivity.setSelectedTab(MainActivity.MORE) - } + mActivity.setSelectedTab(MainActivity.MORE) } } diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/BookGsrFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/BookGsrFragment.kt index d5744d2c6..c2d7c8d34 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/BookGsrFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/BookGsrFragment.kt @@ -8,6 +8,8 @@ import android.content.Context import android.content.Context.ALARM_SERVICE import android.content.Intent import android.os.Build +import android.graphics.Color +import android.graphics.PorterDuff import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -25,7 +27,9 @@ import androidx.fragment.app.FragmentTransaction import androidx.preference.PreferenceManager import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.GSRBookingResult +import kotlinx.android.synthetic.main.gsr_details_book.* import kotlinx.android.synthetic.main.gsr_details_book.view.* +import kotlinx.android.synthetic.main.loading_panel.* import retrofit.Callback import retrofit.RetrofitError import retrofit.client.Response @@ -106,29 +110,38 @@ class BookGsrFragment : Fragment() { } else if (!emailEt.text.toString().matches("""[\w]+@(seas\.|sas\.|wharton\.|nursing\.)?upenn\.edu""".toRegex())) { Toast.makeText(activity, "Please enter a valid Penn email", Toast.LENGTH_LONG).show() } else { - bookGSR(Integer.parseInt(gsrID), Integer.parseInt(gsrLocationCode), startTime, endTime, gid, roomId, roomName) + submit.isClickable = false + submit.background.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY) + loading?.visibility = View.VISIBLE + bookGSR(Integer.parseInt(gsrID), gsrLocationCode, startTime, endTime, gid, roomId, roomName) } } return v } - private fun bookGSR(gsrId: Int, gsrLocationCode: Int, startTime: String?, endTime: String?, gid: Int, roomId: Int, roomName: String) { + private fun bookGSR(gsrId: Int, gsrLocationCode: String, startTime: String?, endTime: String?, gid: Int, roomId: Int, roomName: String) { - var sessionID = "" - var bearerToken = "" - activity?.let { activity -> + + + OAuth2NetworkManager(activity as MainActivity).getAccessToken { + var sessionID = "" + var bearerToken = "" val sp = PreferenceManager.getDefaultSharedPreferences(activity) - sessionID = sp.getString(getString(R.string.huntsmanGSR_SessionID), "") ?: "" - bearerToken = "Bearer " + sp.getString(getString(R.string.access_token), "").toString() - Log.i("BookGSRFragment", "$bearerToken"); + Log.i("Bearer Token", sp.getString(getString(R.string.access_token), "").toString()); + activity?.let { activity -> + val sp = PreferenceManager.getDefaultSharedPreferences(activity) + sessionID = sp.getString(getString(R.string.huntsmanGSR_SessionID), "") ?: "" + bearerToken = "Bearer " + sp.getString(getString(R.string.access_token), "").toString() + Log.i("BookGSRFragment", bearerToken) + } + Log.i("BookGSRFragment", "Bearer $bearerToken") + Log.i("BookGSRFragment", "Start $startTime") + Log.i("BookGSRFragment", "End $endTime") + Log.i("BookGSRFragment", "GID $gid") + Log.i("BookGSRFragment", "ID $roomId") + Log.i("BookGSRFragment", "Room Name $roomName") + - } - Log.i("BookGSRFragment", "Bearer $bearerToken") - Log.i("BookGSRFragment", "Start $startTime") - Log.i("BookGSRFragment", "End $endTime") - Log.i("BookGSRFragment", "GID $gid") - Log.i("BookGSRFragment", "ID $roomId") - Log.i("BookGSRFragment", "Room Name $roomName") mStudentLife.bookGSR( //Passing the values bearerToken, @@ -191,27 +204,19 @@ class BookGsrFragment : Fragment() { Log.e("BookGsrFragment", "GSR booking failed with " + result.getError()) } // go back to GSR fragment - val fragmentManager = (context as MainActivity).supportFragmentManager - fragmentManager.beginTransaction() - .replace(R.id.content_frame, GsrTabbedFragment()) - .addToBackStack("GSR Fragment") - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .commit() + loading?.visibility = View.GONE + activity?.onBackPressed() } override fun failure(error: RetrofitError) { //If any error occurred displaying the error as toast Log.e("BookGSRFragment", "Error booking gsr", error) Toast.makeText(activity, "An error has occurred. Please try again.", Toast.LENGTH_LONG).show() - val fragmentManager = (context as MainActivity).supportFragmentManager - fragmentManager.beginTransaction() - .replace(R.id.content_frame, GsrTabbedFragment()) - .addToBackStack("GSR Fragment") - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .commit() + loading?.visibility = View.GONE + activity?.onBackPressed() } } - ) + )} } @RequiresApi(Build.VERSION_CODES.O) diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/CampusExpressLoginFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/CampusExpressLoginFragment.kt index b34f3abcb..9f24a78ac 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/CampusExpressLoginFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/CampusExpressLoginFragment.kt @@ -2,7 +2,6 @@ package com.pennapps.labs.pennmobile import android.content.SharedPreferences import android.net.Uri -import android.os.Build import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment @@ -92,8 +91,8 @@ class CampusExpressLoginFragment : Fragment() { .build() webView.loadUrl(uri.toString()) val webSettings = webView.settings - webSettings.setJavaScriptEnabled(true) - webSettings.javaScriptCanOpenWindowsAutomatically = true; + webSettings.javaScriptEnabled = true + webSettings.javaScriptCanOpenWindowsAutomatically = true webView.webViewClient = MyWebViewClient() cancelButton.setOnClickListener { @@ -173,13 +172,8 @@ class CampusExpressLoginFragment : Fragment() { val byteArr = md.digest(codeVerifier.toByteArray()) // Base-64 encode - var codeChallenge = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + var codeChallenge = Base64.getEncoder().encodeToString(byteArr) - } else { - String( - android.util.Base64.encode(byteArr, android.util.Base64.DEFAULT), - Charsets.UTF_8) - } // Replace characters to make it web safe codeChallenge = codeChallenge.replace("=", "") diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningFragment.kt index 816a1fb99..9c9d06c58 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningFragment.kt @@ -1,6 +1,5 @@ package com.pennapps.labs.pennmobile -import android.os.Build import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment @@ -12,8 +11,6 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.LinearLayout -import androidx.annotation.RequiresApi -import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.preference.PreferenceManager import com.google.android.material.snackbar.Snackbar import com.google.firebase.analytics.FirebaseAnalytics @@ -21,8 +18,6 @@ import com.pennapps.labs.pennmobile.adapters.DiningAdapter import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.DiningHall import com.pennapps.labs.pennmobile.classes.Venue -import com.pennapps.labs.pennmobile.components.collapsingtoolbar.ToolbarBehavior -import com.pennapps.labs.pennmobile.utils.Utils import kotlinx.android.synthetic.main.fragment_dining.* import kotlinx.android.synthetic.main.fragment_dining.internetConnectionDining import kotlinx.android.synthetic.main.fragment_dining.internetConnection_message_dining @@ -30,6 +25,8 @@ import kotlinx.android.synthetic.main.fragment_dining.view.* import kotlinx.android.synthetic.main.loading_panel.* import kotlinx.android.synthetic.main.no_results.* import rx.Observable +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter class DiningFragment : Fragment() { @@ -55,21 +52,21 @@ class DiningFragment : Fragment() { setHasOptionsMenu(true) } - @RequiresApi(Build.VERSION_CODES.M) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val v = inflater.inflate(R.layout.fragment_dining, container, false) v.dining_swiperefresh?.setColorSchemeResources(R.color.color_accent, R.color.color_primary) v.dining_halls_recycler_view?.layoutManager = LinearLayoutManager(mActivity, LinearLayoutManager.VERTICAL, false) v.dining_swiperefresh.setOnRefreshListener { getDiningHalls() } - getDiningHalls() // initAppBar(v) return v } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + getDiningHalls() } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.dining_sort, menu) val sp = PreferenceManager.getDefaultSharedPreferences(activity) @@ -90,7 +87,6 @@ class DiningFragment : Fragment() { menu.setGroupVisible(R.id.action_sort_by, diningInfoFragment == null || !diningInfoFragment.isVisible) } - @RequiresApi(Build.VERSION_CODES.M) private fun setSortByMethod(method: String) { val sp = PreferenceManager.getDefaultSharedPreferences(activity) val editor = sp.edit() @@ -99,7 +95,6 @@ class DiningFragment : Fragment() { getDiningHalls() } - @RequiresApi(Build.VERSION_CODES.M) override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle presses on the action bar items when (item.itemId) { @@ -126,13 +121,12 @@ class DiningFragment : Fragment() { } } - @RequiresApi(Build.VERSION_CODES.M) private fun getDiningHalls() { //displays banner if not connected if (!isOnline(context)) { internetConnectionDining?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message_dining?.setText("Not Connected to Internet") + internetConnection_message_dining?.text = "Not Connected to Internet" internetConnectionDining?.visibility = View.VISIBLE } else { internetConnectionDining?.visibility = View.GONE @@ -148,6 +142,7 @@ class DiningFragment : Fragment() { .toList() .subscribe({ diningHalls -> mActivity.runOnUiThread { + getMenus(diningHalls) val adapter = DiningAdapter(diningHalls) dining_halls_recycler_view?.adapter = adapter loadingPanel?.visibility = View.GONE @@ -158,14 +153,10 @@ class DiningFragment : Fragment() { view?.let {displaySnack(it, "Just Updated")} } }, { - Log.e("DiningFragment", "Error getting dining halls", it); + Log.e("DiningFragment", "Error getting dining halls", it) mActivity.runOnUiThread { Log.e("Dining", "Could not load Dining page", it) loadingPanel?.visibility = View.GONE - //internetConnectionDining?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - //internetConnection_message_dining?.text = getString(R.string.internet_error) - //internetConnectionDining?.visibility = View.VISIBLE - no_results?.visibility = View.VISIBLE dining_swiperefresh?.isRefreshing = false } }) @@ -175,9 +166,7 @@ class DiningFragment : Fragment() { super.onResume() mActivity.removeTabs() mActivity.setTitle(R.string.dining) - if (Build.VERSION.SDK_INT > 17) { - mActivity.setSelectedTab(MainActivity.DINING) - } + mActivity.setSelectedTab(MainActivity.DINING) } @@ -187,13 +176,8 @@ class DiningFragment : Fragment() { @Suppress("DEPRECATION") private fun displaySnack(view: View, text: String) { val snackBar = Snackbar.make(view.snack_bar_dining, text, Snackbar.LENGTH_SHORT) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - snackBar.setTextColor(resources.getColor(R.color.white, context?.theme)) - snackBar.setBackgroundTint(resources.getColor(R.color.penn_mobile_grey, context?.theme)) - } else { - snackBar.setTextColor(resources.getColor(R.color.white)) - snackBar.setBackgroundTint(resources.getColor(R.color.penn_mobile_grey)) - } + snackBar.setTextColor(resources.getColor(R.color.white, context?.theme)) + snackBar.setBackgroundTint(resources.getColor(R.color.penn_mobile_grey, context?.theme)) // SnackBar message and action TextViews are placed inside a LinearLayout val snackBarLayout = snackBar.view as Snackbar.SnackbarLayout for (i in 0 until snackBarLayout.childCount) { @@ -207,6 +191,28 @@ class DiningFragment : Fragment() { } companion object { + // Gets the dining hall menus + fun getMenus(venues: MutableList) : Unit { + val idVenueMap = mutableMapOf() + venues.forEach { idVenueMap[it.id] = it } + val current = LocalDateTime.now() + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val formatted = current.format(formatter) + val studentLife = MainActivity.studentLifeInstance + studentLife.getMenus(formatted).subscribe({ menus -> + menus.forEach { menu -> + val id = menu.venue?.venue_id + val diningHall = idVenueMap[id] + val diningHallMenus = diningHall?.menus ?: mutableListOf() + diningHallMenus.add(menu) + diningHall?.sortMeals(diningHallMenus) + } + }, { throwable -> + Log.e("DiningFragment", "Error getting Menus", throwable) + }) + + } + // Takes a venue then adds an image and modifies venue name if name is too long fun createHall(venue: Venue): DiningHall { when (venue.id) { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningHolderFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningHolderFragment.kt index 69acc95e0..755d0107a 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningHolderFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningHolderFragment.kt @@ -1,30 +1,19 @@ package com.pennapps.labs.pennmobile -import android.os.Build import android.os.Bundle -import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.LinearLayout -import androidx.annotation.RequiresApi import androidx.coordinatorlayout.widget.CoordinatorLayout -import com.google.android.material.snackbar.Snackbar import com.google.android.material.tabs.TabLayoutMediator -import com.pennapps.labs.pennmobile.adapters.DiningAdapter import com.pennapps.labs.pennmobile.adapters.DiningPagerAdapter -import com.pennapps.labs.pennmobile.classes.DiningHall -import com.pennapps.labs.pennmobile.classes.Venue import com.pennapps.labs.pennmobile.components.collapsingtoolbar.ToolbarBehavior import com.pennapps.labs.pennmobile.utils.Utils -import kotlinx.android.synthetic.main.fragment_dining.* import kotlinx.android.synthetic.main.fragment_dining.view.* import kotlinx.android.synthetic.main.fragment_dining_holder.* import kotlinx.android.synthetic.main.fragment_dining_holder.view.* -import kotlinx.android.synthetic.main.loading_panel.* -import kotlinx.android.synthetic.main.no_results.* -import rx.Observable + class DiningHolderFragment : Fragment() { @@ -35,10 +24,8 @@ class DiningHolderFragment : Fragment() { super.onCreate(savedInstanceState) mActivity = activity as MainActivity mActivity.closeKeyboard() - } - @RequiresApi(Build.VERSION_CODES.M) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_dining_holder, container, false) @@ -53,11 +40,11 @@ class DiningHolderFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) pagerAdapter = DiningPagerAdapter(childFragmentManager, lifecycle) - pager?.setAdapter(pagerAdapter) - pager.setUserInputEnabled(false) + pager?.adapter = pagerAdapter + pager.isUserInputEnabled = false TabLayoutMediator(tabLayout, pager) { tab, position -> if (position == 0) { - tab.text = "Dining" + tab.text = "Dining Halls" } else { tab.text = "Insights" } @@ -65,18 +52,15 @@ class DiningHolderFragment : Fragment() { setTitle("Dining") } - @RequiresApi(Build.VERSION_CODES.M) private fun getConnected() { //displays banner if not connected if (!isOnline(context)) { internetConnectionDiningHolder?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) internetConnection_message_dining_holder?.text = getString(R.string.internet_error) internetConnectionDiningHolder?.visibility = View.VISIBLE - // loadingPanel?.visibility = View.GONE + //loadingPanel?.visibility = View.GONE } else { internetConnectionDiningHolder?.visibility = View.GONE - // loadingPanel?.visibility = View.GONE - // dining_swiperRefresh_holder?.isRefreshing = false } } @@ -85,19 +69,17 @@ class DiningHolderFragment : Fragment() { mActivity.removeTabs() //mActivity.toolbar.visibility = View.GONE mActivity.setTitle(R.string.dining) - if (Build.VERSION.SDK_INT > 17) { - mActivity.setSelectedTab(MainActivity.DINING) - } + mActivity.setSelectedTab(MainActivity.DINING) } private fun initAppBar(view: View) { - if (Build.VERSION.SDK_INT > 16) { - (view.appbar_home_holder.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() - } + (view.appbar_home_holder.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() view.date_view.text = Utils.getCurrentSystemTime() } private fun setTitle(title: CharSequence) { title_view.text = title } + + } \ No newline at end of file diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInfoFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInfoFragment.kt index 7a5bd9d9d..3fd1b824f 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInfoFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInfoFragment.kt @@ -3,7 +3,6 @@ package com.pennapps.labs.pennmobile import android.content.Context import android.graphics.Color import android.net.ConnectivityManager -import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -61,7 +60,7 @@ class DiningInfoFragment : Fragment() { } private fun hasMeals(day: VenueInterval): Boolean { - return day.meals.isNotEmpty(); + return day.meals.isNotEmpty() } private fun addDiningHour(day: VenueInterval, vertical: ArrayList): ArrayList { @@ -73,9 +72,7 @@ class DiningInfoFragment : Fragment() { textView.text = dateString textView.setTextAppearance(mActivity, R.style.DiningInfoDate) textView.setPadding(0, 40, 0, 0) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - textView.typeface = resources.getFont(R.font.gilroy_light) - } + textView.typeface = resources.getFont(R.font.gilroy_light) textView.setTextColor(resources.getColor(R.color.color_primary_dark)) if (vertical.isEmpty()) { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInsightsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInsightsFragment.kt index b816d6852..2acbc0561 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInsightsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningInsightsFragment.kt @@ -1,13 +1,11 @@ package com.pennapps.labs.pennmobile -import android.os.Build import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.annotation.RequiresApi import androidx.fragment.app.FragmentTransaction import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -15,21 +13,19 @@ import com.pennapps.labs.pennmobile.adapters.DiningInsightsCardAdapter import com.pennapps.labs.pennmobile.api.CampusExpress import com.pennapps.labs.pennmobile.api.CampusExpressNetworkManager import com.pennapps.labs.pennmobile.classes.DiningBalances +import com.pennapps.labs.pennmobile.classes.DiningBalancesList import com.pennapps.labs.pennmobile.classes.DiningInsightCell import com.pennapps.labs.pennmobile.classes.DollarsSpentCell -import kotlinx.android.synthetic.main.fragment_dining.* -import kotlinx.android.synthetic.main.fragment_dining.view.* import kotlinx.android.synthetic.main.fragment_dining_insights.* import kotlinx.android.synthetic.main.fragment_dining_insights.view.* -import kotlinx.android.synthetic.main.fragment_home.view.* -import java.util.* +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter import kotlin.collections.ArrayList /** - * A simple [Fragment] subclass. - * Use the [DiningInsightsFragment.newInstance] factory method to - * create an instance of this fragment. + * Dining Insights Fragment + * Created by Julius Snipes */ class DiningInsightsFragment : Fragment() { @@ -38,7 +34,6 @@ class DiningInsightsFragment : Fragment() { private lateinit var networkManager: CampusExpressNetworkManager private lateinit var cells : ArrayList private lateinit var insightsrv : RecyclerView - @RequiresApi(Build.VERSION_CODES.O) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -47,7 +42,6 @@ class DiningInsightsFragment : Fragment() { mActivity.closeKeyboard() } - @RequiresApi(Build.VERSION_CODES.O) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_dining_insights, container, false) @@ -59,8 +53,14 @@ class DiningInsightsFragment : Fragment() { networkManager = CampusExpressNetworkManager(mActivity) val diningBalance = DollarsSpentCell() diningBalance.type = "dining_balance" + val diningDollarsPredictionsCell = DiningInsightCell() + diningDollarsPredictionsCell.type = "dining_dollars_predictions" + val diningSwipesPredictionsCell = DiningInsightCell() + diningSwipesPredictionsCell.type = "dining_swipes_predictions" cells = ArrayList() cells.add(diningBalance) + cells.add(diningDollarsPredictionsCell) + cells.add(diningSwipesPredictionsCell) insightsrv = view.insightsrv insightsrv.adapter = DiningInsightsCardAdapter(cells) val networkManager = CampusExpressNetworkManager(mActivity) @@ -79,6 +79,18 @@ class DiningInsightsFragment : Fragment() { } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + if (!isOnline(context)) { + internetConnectionDiningInsights?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) + internetConnection_message_dining_insights?.setText("Not Connected to Internet") + internetConnectionDiningInsights?.visibility = View.VISIBLE + dining_insights_refresh?.isRefreshing = false + return + } else { + internetConnectionDiningInsights?.visibility = View.GONE + } + } override fun onResume() { super.onResume() @@ -104,6 +116,15 @@ class DiningInsightsFragment : Fragment() { private fun getInsights(accessToken: String?) { + if (!isOnline(context)) { + internetConnectionDiningInsights?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) + internetConnection_message_dining_insights?.setText("Not Connected to Internet") + internetConnectionDiningInsights?.visibility = View.VISIBLE + dining_insights_refresh?.isRefreshing = false + return + } else { + internetConnectionDiningInsights?.visibility = View.GONE + } val bearerToken = "Bearer $accessToken" mCampusExpress.getCurrentDiningBalances(bearerToken).subscribe( { t: DiningBalances? -> activity?.runOnUiThread { @@ -118,6 +139,23 @@ class DiningInsightsFragment : Fragment() { dining_insights_refresh?.isRefreshing = false } }) + val current = LocalDateTime.now() + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val formattedCurrentDate = current.format(formatter) + mCampusExpress.getPastDiningBalances(bearerToken, DiningInsightsCardAdapter.START_DAY_OF_SEMESTER, formattedCurrentDate).subscribe( { t: DiningBalancesList? -> + activity?.runOnUiThread { + cells[1].diningBalancesList = t + cells[2].diningBalancesList = t + (insightsrv.adapter as DiningInsightsCardAdapter).notifyItemChanged(1) + (insightsrv.adapter as DiningInsightsCardAdapter).notifyItemChanged(2) + dining_insights_refresh?.isRefreshing = false + } }, + { throwable -> + activity?.runOnUiThread { + Log.e("DiningInsightsFragment", "Error getting balances", throwable) + dining_insights_refresh?.isRefreshing = false + } + }) } diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningSettingsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningSettingsFragment.kt index 73b4a11dd..da8d360b9 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningSettingsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/DiningSettingsFragment.kt @@ -8,18 +8,18 @@ import androidx.fragment.app.Fragment import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import com.pennapps.labs.pennmobile.adapters.DiningSettingsAdapter -import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.api.OAuth2NetworkManager +import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.DiningHall +import com.pennapps.labs.pennmobile.classes.DiningRequest import kotlinx.android.synthetic.main.fragment_dining_preferences.* import kotlinx.android.synthetic.main.fragment_dining_preferences.view.* import kotlinx.android.synthetic.main.include_main.* -import kotlinx.android.synthetic.main.fragment_dining_preferences.view.* import retrofit.ResponseCallback import retrofit.RetrofitError import retrofit.client.Response import rx.Observable -import java.util.* + class DiningSettingsFragment : Fragment() { private lateinit var mActivity: MainActivity @@ -92,28 +92,32 @@ class DiningSettingsFragment : Fragment() { val sp = PreferenceManager.getDefaultSharedPreferences(mActivity) val favoriteDiningHalls = ArrayList() + for (hall in halls) { if (sp.getBoolean(hall.name, false)) { favoriteDiningHalls.add(hall.id) } } - - //preferences must be in the form of 1,2,3 (exclude brackets) - var apiPreparedString = favoriteDiningHalls.toString() - apiPreparedString = apiPreparedString.substring(1, apiPreparedString.length - 1) - val bearerToken = "Bearer " + sp.getString(getString(R.string.access_token), "").toString() - mStudentLife.sendDiningPref(bearerToken, apiPreparedString, + OAuth2NetworkManager(activity as MainActivity).getAccessToken { + val bearerToken = + "Bearer " + sp.getString(getString(R.string.access_token), "").toString() + mStudentLife.sendDiningPref(bearerToken, DiningRequest(favoriteDiningHalls), object : ResponseCallback() { - override fun success(response: Response) { - mActivity.onBackPressed() - } + override fun success(response: Response) { + mActivity.onBackPressed() + } - override fun failure(error: RetrofitError) { - Log.e("Dining", "Error saving dining preferences: $error") - Toast.makeText(mActivity, "Error saving dining preferences", Toast.LENGTH_SHORT).show() - } - }) + override fun failure(error: RetrofitError) { + Log.e("Dining", "Error saving dining preferences: $error") + Toast.makeText( + mActivity, + "Error saving dining preferences", + Toast.LENGTH_SHORT + ).show() + } + }) + } } -} \ No newline at end of file +} diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessFragment.kt index dbae8c0cb..8c6b4c1e6 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessFragment.kt @@ -1,6 +1,5 @@ package com.pennapps.labs.pennmobile -import android.os.Build import android.os.Bundle import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager @@ -8,7 +7,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast -import androidx.annotation.RequiresApi import com.google.firebase.analytics.FirebaseAnalytics import com.pennapps.labs.pennmobile.adapters.FitnessAdapter import kotlinx.android.synthetic.main.fragment_fitness.* @@ -49,14 +47,12 @@ class FitnessFragment : Fragment() { return view } - @RequiresApi(Build.VERSION_CODES.M) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { view.gym_refresh_layout?.setOnRefreshListener { getGymData() } // get api data getGymData() } - @RequiresApi(Build.VERSION_CODES.M) private fun getGymData() { //displays banner if not connected @@ -68,38 +64,12 @@ class FitnessFragment : Fragment() { internetConnectionFitness?.visibility = View.GONE } - // get API data - val labs = MainActivity.studentLifeInstance - labs.gymData.subscribe({ gyms -> - mActivity.runOnUiThread { - gym_list?.adapter = FitnessAdapter(gyms) - // get rid of loading screen - loadingPanel?.visibility = View.GONE - if (gyms.size > 0) { - no_results?.visibility = View.GONE - } else { - no_results?.visibility = View.VISIBLE - } - // stop refreshing - gym_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - throwable.printStackTrace() - Toast.makeText(activity, "Could not load gym information", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - no_results?.visibility = View.VISIBLE - gym_refresh_layout?.isRefreshing = false - } - }) } override fun onResume() { super.onResume() mActivity.removeTabs() mActivity.setTitle(R.string.fitness) - if (Build.VERSION.SDK_INT > 17){ - mActivity.setSelectedTab(MainActivity.MORE) - } + mActivity.setSelectedTab(MainActivity.MORE) } } \ No newline at end of file diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessHolderFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessHolderFragment.kt new file mode 100644 index 000000000..e0884feda --- /dev/null +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessHolderFragment.kt @@ -0,0 +1,69 @@ +package com.pennapps.labs.pennmobile + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.fragment.app.Fragment +import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.tabs.TabLayoutMediator +import com.pennapps.labs.pennmobile.adapters.FitnessPagerAdapter +import com.pennapps.labs.pennmobile.components.collapsingtoolbar.ToolbarBehavior +import com.pennapps.labs.pennmobile.utils.Utils + +import kotlinx.android.synthetic.main.fragment_fitness_holder.pager +import kotlinx.android.synthetic.main.fragment_fitness_holder.tabLayout + +class FitnessHolderFragment: Fragment() { + private lateinit var mActivity : MainActivity + private lateinit var mView : View + private lateinit var pagerAdapter : FitnessPagerAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mActivity = activity as MainActivity + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + super.onCreateView(inflater, container, savedInstanceState) + return inflater.inflate(R.layout.fragment_fitness_holder, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mView = view + // initialize app bar and swipe refresh + initAppBar() + + pagerAdapter = FitnessPagerAdapter(this) + pager?.adapter = pagerAdapter + pager.isUserInputEnabled = false + TabLayoutMediator(tabLayout, pager) { tab, position -> + if (position == 0) { + tab.text = "Pottruck" + } else { + tab.text = "Favorites" + } + }.attach() + } + + /** + * Initialize the app bar of the fragment and + * fills in the textViews for the title/date + */ + private fun initAppBar() { + val appBarLayout : AppBarLayout = mView.findViewById(R.id.appbar_home_holder) + val titleView : TextView = mView.findViewById(R.id.title_view) + val dateView : TextView = mView.findViewById(R.id.date_view) + + (appBarLayout.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() + titleView.text = getString(R.string.fitness) + dateView.text = Utils.getCurrentSystemTime() + } +} \ No newline at end of file diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessPreferencesFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessPreferencesFragment.kt new file mode 100644 index 000000000..0b6cc0ce7 --- /dev/null +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FitnessPreferencesFragment.kt @@ -0,0 +1,66 @@ +package com.pennapps.labs.pennmobile + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.DialogFragment +import androidx.recyclerview.widget.RecyclerView +import com.pennapps.labs.pennmobile.adapters.FitnessPreferenceAdapter +import com.pennapps.labs.pennmobile.classes.FitnessPreferenceViewModel + +interface CloseListener { + fun updateAdapters() +} + +class FitnessPreferencesFragment(private val dataModel: FitnessPreferenceViewModel, + private val listener: CloseListener) : DialogFragment() { + + private lateinit var mActivity : MainActivity + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + mActivity = activity as MainActivity + return inflater.inflate(R.layout.fragment_fitness_preferences, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val prefAdapter = FitnessPreferenceAdapter(dataModel) + + val recyclerView: RecyclerView = view.findViewById(R.id.fitness_preference_recycler_view) + recyclerView.adapter = prefAdapter + + val cancelText : TextView = view.findViewById(R.id.fitness_fragment_pref_cancel) + cancelText.setOnClickListener { + dataModel.restorePreferences() + dialog?.dismiss() + } + + val saveText : TextView = view.findViewById(R.id.fitness_fragment_pref_save) + saveText.setOnClickListener { + dataModel.updatePositionMap() + dataModel.updateRemotePreferences(mActivity) + listener.updateAdapters() + + dialog?.dismiss() + } + } + + override fun onStart() { + super.onStart() + val dialog = dialog + + if (dialog != null) { + val width = ViewGroup.LayoutParams.MATCH_PARENT + val height = ViewGroup.LayoutParams.MATCH_PARENT + dialog.window!!.setLayout(width, height) + } + } + +} \ No newline at end of file diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FlingFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FlingFragment.kt index f2bf0ba4b..e2a791348 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FlingFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/FlingFragment.kt @@ -45,7 +45,6 @@ class FlingFragment : Fragment() { val builder = Builder() val customTabsIntent = builder.build() customTabsIntent.launchUrl(mActivity, Uri.parse(url)) - true } } return super.onOptionsItemSelected(item) diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrFragment.kt index 1e50b9199..0c6c8fb5c 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrFragment.kt @@ -12,17 +12,15 @@ import android.view.View import android.view.ViewGroup import android.widget.* import android.widget.AdapterView.OnItemSelectedListener -import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.annotation.RequiresApi +import androidx.preference.PreferenceManager import com.google.firebase.analytics.FirebaseAnalytics import com.pennapps.labs.pennmobile.adapters.GsrBuildingAdapter +import com.pennapps.labs.pennmobile.api.OAuth2NetworkManager import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.GSRContainer import com.pennapps.labs.pennmobile.classes.GSRRoom import com.pennapps.labs.pennmobile.classes.GSRSlot -import com.pennapps.labs.pennmobile.components.collapsingtoolbar.ToolbarBehavior -import com.pennapps.labs.pennmobile.utils.Utils -import kotlinx.android.synthetic.main.fragment_dining.view.* import kotlinx.android.synthetic.main.fragment_gsr.* import kotlinx.android.synthetic.main.fragment_gsr.view.* import org.joda.time.DateTime @@ -40,12 +38,13 @@ class GsrFragment : Fragment() { lateinit var durationDropDown: Spinner lateinit var loadingPanel: LinearLayout lateinit var noResultsPanel: LinearLayout + lateinit var sortingSwitch: Switch // api manager private lateinit var mStudentLife: StudentLife //list that holds all GSR rooms - private val gsrHashMap = HashMap() + private val gsrHashMap = HashMap() //list that holds all GSR rooms and their gids private val gsrGIDHashMap = HashMap() @@ -61,7 +60,14 @@ class GsrFragment : Fragment() { private val gsrSlotFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZZ") private lateinit var durationAdapter: ArrayAdapter - private lateinit var huntsmanDurationAdapter: ArrayAdapter + private lateinit var whartonDurationAdapter: ArrayAdapter + private lateinit var biotechDurationAdapter: ArrayAdapter + + private var populatedDropDownGSR = false + + private var bearerToken = "" + private var isWharton = false + private var sortByTime = false private lateinit var mActivity: MainActivity @@ -93,10 +99,15 @@ class GsrFragment : Fragment() { durationDropDown = view.gsr_duration loadingPanel = view.gsr_loading noResultsPanel = view.gsr_no_results + sortingSwitch = view.sorting_switch + sortByTime = sortingSwitch.isChecked durationAdapter = ArrayAdapter(mActivity, R.layout.gsr_spinner_item, arrayOf("30m", "60m", "90m", "120m")) - huntsmanDurationAdapter = ArrayAdapter(mActivity, R.layout.gsr_spinner_item, arrayOf("30m", "60m", "90m")) + whartonDurationAdapter = ArrayAdapter(mActivity, R.layout.gsr_spinner_item, arrayOf("30m", "60m", "90m")) + biotechDurationAdapter = ArrayAdapter(mActivity, R.layout.gsr_spinner_item, arrayOf("30m", "60m", "90m", "120m", "150m", "180m")) + // update user status by getting the bearer token and checking wharton status + updateStatus() // populate the list of gsrs populateDropDownGSR() @@ -172,57 +183,117 @@ class GsrFragment : Fragment() { datePickerDialog.show() } + sortingSwitch.setOnClickListener{ + sortByTime = sortingSwitch.isChecked + searchForGSR(false) + } // handle swipe to refresh view.gsr_refresh_layout?.setColorSchemeResources(R.color.color_accent, R.color.color_primary) view.gsr_refresh_layout?.setOnRefreshListener { + updateStatus() searchForGSR(true) } + internetConnectionGSR?.visibility = View.VISIBLE } - @RequiresApi(Build.VERSION_CODES.M) override fun onResume() { super.onResume() - val mActivity : MainActivity? = activity as MainActivity - mActivity?.removeTabs() - mActivity?.setTitle(R.string.gsr) - if (Build.VERSION.SDK_INT > 17){ - mActivity?.setSelectedTab(MainActivity.GSR) + } + + private fun updateStatus() { + OAuth2NetworkManager(mActivity).getAccessToken { + val sp = PreferenceManager.getDefaultSharedPreferences(activity) + bearerToken = sp.getString(getString(R.string.access_token), "").toString(); + + if (bearerToken.isNullOrEmpty()) { + Toast.makeText(activity, "You are not logged in!", Toast.LENGTH_LONG).show() + } else { + mStudentLife.isWharton( + "Bearer $bearerToken" + ) + ?.subscribe({ status -> + isWharton = status.isWharton + }, { + Log.e("GsrFragment", "Error getting Wharton status", it) + isWharton = false + } + ) + } } - populateDropDownGSR() } // Performs GSR search // Called when page loads and whenever user changes start/end time, date, or building - @RequiresApi(Build.VERSION_CODES.M) fun searchForGSR(calledByRefreshLayout: Boolean) { + //displays banner if not connected + if (!isOnline(context)) { + internetConnectionGSR?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) + internetConnection_message_gsr?.setText("Not Connected to Internet") + internetConnectionGSR?.visibility = View.VISIBLE + } else { + internetConnectionGSR?.visibility = View.GONE + if(!populatedDropDownGSR) { + populateDropDownGSR() + } + } var gsrLocation = gsrLocationDropDown.selectedItem.toString() val location = mapGSR(gsrLocation) val gid = mapGID(gsrLocation) - if (location == -1) { - showNoResults() - } else { - // display loading screen if user did not use swipe refresh - if (!calledByRefreshLayout) { - loadingPanel.visibility = View.VISIBLE - gsr_rooms_list?.visibility = View.GONE + OAuth2NetworkManager(mActivity).getAccessToken { + val sp = PreferenceManager.getDefaultSharedPreferences(activity) + bearerToken = sp.getString(getString(R.string.access_token), "").toString(); + + if (location.isNullOrEmpty() || bearerToken.isNullOrEmpty()) { + showNoResults() + } else { + // display loading screen if user did not use swipe refresh + if (!calledByRefreshLayout) { + loadingPanel.visibility = View.VISIBLE + gsr_rooms_list?.visibility = View.GONE + } + + if (!isWharton && (location == "ARB" || location == "JMHH")) { + showNoResults() + if (!calledByRefreshLayout) { + Toast.makeText( + activity, + "You need to have a Wharton pennkey to access Wharton GSRs", + Toast.LENGTH_LONG + ).show() + } + } else { + noResultsPanel.visibility = View.GONE + gsr_no_rooms?.visibility = View.GONE + // get the hours + getTimes(location, gid) + } } - noResultsPanel.visibility = View.GONE - gsr_no_rooms?.visibility = View.GONE - //get the hours - getTimes(location, gid) } } // Performs GET request and fetches the rooms and availability - private fun getTimes(location: Int, gId: Int) { + private fun getTimes(location: String, gId: Int) { val adjustedDateString = selectedDateTime.toString(adjustedDateFormat) selectDateButton.isClickable = false selectTimeButton.isClickable = false gsrLocationDropDown.isEnabled = false durationDropDown.isEnabled = false - mStudentLife.gsrRoom(location, gId, adjustedDateString) + sortingSwitch.isClickable = false + + + OAuth2NetworkManager(mActivity).getAccessToken { + val sp = PreferenceManager.getDefaultSharedPreferences(activity) + bearerToken = sp.getString(getString(R.string.access_token), "").toString(); + + Log.i("GsrFragment", "Bearer Token: $bearerToken"); + Log.i("GsrFragment", "Wharton Status: $isWharton") + + mStudentLife.gsrRoom( + "Bearer $bearerToken", + location, gId, adjustedDateString + ) ?.subscribe({ gsr -> - activity?.let {activity -> + activity?.let { activity -> activity.runOnUiThread { val gsrRooms = gsr.rooms var timeSlotLengthZero = true @@ -256,7 +327,8 @@ class GsrFragment : Fragment() { } gsr_rooms_list?.adapter = (context?.let { - GsrBuildingAdapter(it, mGSRS, location.toString(), (durationDropDown.selectedItemPosition + 1) * 30) + GsrBuildingAdapter(it, mGSRS, location.toString(), (durationDropDown.selectedItemPosition + 1) * 30, sortByTime) + }) mGSRS = ArrayList() @@ -264,21 +336,26 @@ class GsrFragment : Fragment() { selectTimeButton.isClickable = true gsrLocationDropDown.isEnabled = true durationDropDown.isEnabled = true + sortingSwitch.isClickable = true + } } }, { Log.e("GsrFragment", "Error getting gsr times", it) - activity?.let { - activity -> - activity.runOnUiThread { - showNoResults() - selectDateButton.isClickable = true - selectTimeButton.isClickable = true - gsrLocationDropDown.isEnabled = true - durationDropDown.isEnabled = true - } } + activity?.let { activity -> + activity.runOnUiThread { + showNoResults() + selectDateButton.isClickable = true + selectTimeButton.isClickable = true + gsrLocationDropDown.isEnabled = true + durationDropDown.isEnabled = true + sortingSwitch.isClickable = true + + } + } } ) + } } private fun filterInsertTimeSlots(gsrRoom: GSRRoom, timeSlots: Array, gid: Int) { @@ -328,13 +405,11 @@ class GsrFragment : Fragment() { } } - - @RequiresApi(Build.VERSION_CODES.M) private fun populateDropDownGSR() { - mStudentLife.location() ?.subscribe({ locations -> activity?.let {activity -> + populatedDropDownGSR = true activity.runOnUiThread { //reset the drop down val emptyArray = arrayOfNulls(0) @@ -343,72 +418,16 @@ class GsrFragment : Fragment() { gsrLocationDropDown.adapter = emptyAdapter val numLocations = locations.size - var i = 0 // go through all the rooms while (i < numLocations) { val locationName = locations[i]?.name ?: "" - when (locations[i].id) { - 1086 -> { - if (locations[i].name.equals("VP Ground Floor")) { - gsrHashMap["VP Ground Floor"] = 1086 - gsrGIDHashMap["VP Ground Floor"] = locations[i].gid - } else if (locations[i].name.equals("Weigle")) { - gsrHashMap["Weigle"] = 1086 - gsrGIDHashMap["Weigle"] = locations[i].gid - } else if (locations[i].name.equals("VP 3rd Floor")) { - gsrHashMap["VP 3rd Floor"] = 1086 - gsrGIDHashMap["VP 3rd Floor"] = locations[i].gid - } else if (locations[i].name.equals("VP 4th Floor")) { - gsrHashMap["VP 4th Floor"] = 1086 - gsrGIDHashMap["VP 4th Floor"] = locations[i].gid - } - } - 2587 -> { - gsrHashMap["Lippincott"] = 2587 - gsrGIDHashMap["Lippincott"] = locations[i].gid - } - 2495 -> { - gsrHashMap["Edu Commons"] = 2495 - gsrGIDHashMap["Edu Commons"] = locations[i].gid - } - 2683 -> { - gsrHashMap["Biomedical"] = 2683 - gsrGIDHashMap["Biomedical"] = locations[i].gid - } - 2637 -> { - gsrHashMap["Fisher"] = 2637 - gsrGIDHashMap["Fisher"] = locations[i].gid - } - 1090 -> { - gsrHashMap["Levin Building"] = 1090 - gsrGIDHashMap["Levin Building"] = locations[i].gid - } - 2634 -> { - gsrHashMap["Museum Library"] = 2634 - gsrGIDHashMap["Museum Library"] = locations[i].gid - } - 2636 -> { - gsrHashMap["VP Seminar"] = 2636 - gsrGIDHashMap["VP Seminar"] = locations[i].gid - } - 2611 -> { - gsrHashMap["VP Special Use"] = 2611 - gsrGIDHashMap["VP Special Use"] = locations[i].gid - } - 1 -> { - gsrHashMap["Huntsman Hall"] = 1 - gsrGIDHashMap["Huntsman Hall"] = locations[i].gid - } - 4370 -> { - gsrHashMap["PCPSE Building"] = 4370 - gsrGIDHashMap["PCPSE Building"] = locations[i].gid - } - else -> { - gsrHashMap[locationName] = locations[i].id - gsrGIDHashMap[locationName] = locations[i].gid - } + if (locationName.isNullOrEmpty()) { + Log.w("Empty location name", + locations[i].id ?: locations[i].gid.toString()); } + gsrHashMap[locationName] = locations[i].id + gsrGIDHashMap[locationName] = locations[i].gid i++ } @@ -417,8 +436,10 @@ class GsrFragment : Fragment() { val adapter = ArrayAdapter(activity, R.layout.gsr_spinner_item, gsrs) gsrLocationDropDown.adapter = adapter - durationDropDown.adapter = if (gsrLocationDropDown.selectedItem.toString() == "Huntsman Hall") - huntsmanDurationAdapter else durationAdapter + durationDropDown.adapter = if (gsrLocationDropDown.selectedItem.toString() == "Huntsman" + || gsrLocationDropDown.selectedItem.toString() == "Academic Research") + whartonDurationAdapter else if (gsrLocationDropDown.selectedItem.toString() == "Biomedical") + biotechDurationAdapter else durationAdapter searchForGSR(false) } } @@ -427,25 +448,28 @@ class GsrFragment : Fragment() { activity?.let { activity -> activity.runOnUiThread { //hard coded in case runs into error - gsrHashMap["VP Ground Floor"] = 1086 - gsrHashMap["Weigle"] = 1086 - gsrHashMap["Lippincott"] = 2587 - gsrHashMap["Edu Commons"] = 2495 - gsrHashMap["Biomedical"] = 2683 - gsrHashMap["Fisher"] = 2637 - gsrHashMap["Levin Building"] = 1090 - gsrHashMap["Museum Library"] = 2634 - gsrHashMap["VP Seminar"] = 2636 - gsrHashMap["VP Special Use"] = 2611 - gsrHashMap["Huntsman Hall"] = 1 - gsrHashMap["PCPSE Building"] = 4370 + gsrHashMap["VP Ground Floor"] = "1086" + gsrHashMap["Weigle"] = "1086" + gsrHashMap["Lippincott"] = "2587" + gsrHashMap["Edu Commons"] = "2495" + gsrHashMap["Biotech Commons"] = "2683" + gsrHashMap["Fisher"] = "2637" + gsrHashMap["Levin Building"] = "1090" + gsrHashMap["Museum Library"] = "2634" + gsrHashMap["VP Seminar"] = "2636" + gsrHashMap["VP Special Use"] = "2611" + gsrHashMap["Huntsman Hall"] = "JMHH" + gsrHashMap["Academic Research"] = "ARB" + gsrHashMap["PCPSE Building"] = "4370" gsrGIDHashMap["PCPSE Building"] = 7426 val gsrs = gsrHashMap.keys.toList().toTypedArray() val adapter = ArrayAdapter(activity, R.layout.gsr_spinner_item, gsrs) gsrLocationDropDown.adapter = adapter - durationDropDown.adapter = if (gsrLocationDropDown.selectedItem.toString() == "Huntsman Hall") - huntsmanDurationAdapter else durationAdapter + durationDropDown.adapter = if (gsrLocationDropDown.selectedItem.toString() == "Huntsman" + || gsrLocationDropDown.selectedItem.toString() == "Academic Research") + whartonDurationAdapter else if (gsrLocationDropDown.selectedItem.toString() == "Biotech Commons") + biotechDurationAdapter else durationAdapter searchForGSR(false) } } @@ -454,8 +478,18 @@ class GsrFragment : Fragment() { gsrLocationDropDown.onItemSelectedListener = object : OnItemSelectedListener { override fun onItemSelected(adapterView: AdapterView<*>, view: View?, i: Int, l: Long) { // change possible durations depending on the location - durationDropDown.adapter = if (gsrLocationDropDown.selectedItem.toString() == "Huntsman Hall") - huntsmanDurationAdapter else durationAdapter + var durationPos = durationDropDown.selectedItemPosition + if (durationPos >= 3 && (gsrLocationDropDown.selectedItem.toString() == "Huntsman" + || gsrLocationDropDown.selectedItem.toString() == "Academic Research")) { + durationPos = 2 + } else if (durationPos > 3 && gsrLocationDropDown.selectedItem.toString() != "Biotech Commons") { + durationPos = 3 + } + durationDropDown.adapter = if (gsrLocationDropDown.selectedItem.toString() == "Huntsman" + || gsrLocationDropDown.selectedItem.toString() == "Academic Research") + whartonDurationAdapter else if (gsrLocationDropDown.selectedItem.toString() == "Biotech Commons") + biotechDurationAdapter else durationAdapter + durationDropDown.setSelection(durationPos) searchForGSR(false) } @@ -484,7 +518,7 @@ class GsrFragment : Fragment() { } //takes the name of the gsr and returns an int for the corresponding code - fun mapGSR(name: String): Int = gsrHashMap[name] ?: 0 + fun mapGSR(name: String): String = gsrHashMap[name] ?: "" //takes the name of the gsr and returns an int for the corresponding gid fun mapGID(name: String): Int = gsrGIDHashMap[name] ?: 0 diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrReservationsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrReservationsFragment.kt index c325074f3..1daa1cf94 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrReservationsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrReservationsFragment.kt @@ -53,37 +53,64 @@ class GsrReservationsFragment : Fragment() { return view } - private fun getReservations() { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + if (!isOnline(context)) { + internetConnectionGSRReservations?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) + internetConnection_message_gsr_reservations?.text = "Not Connected to Internet" + internetConnectionGSRReservations?.visibility = View.VISIBLE + gsr_reservations_refresh_layout?.isRefreshing = false + loadingPanel?.visibility = View.GONE + gsr_no_reservations?.visibility = View.VISIBLE + } else { + internetConnectionGSRReservations?.visibility = View.GONE + } + } + private fun getReservations() { + if (!isOnline(context)) { + internetConnectionGSRReservations?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) + internetConnection_message_gsr_reservations?.text = "Not Connected to Internet" + internetConnectionGSRReservations?.visibility = View.VISIBLE + gsr_reservations_refresh_layout?.isRefreshing = false + gsr_reservations_rv?.adapter = GsrReservationsAdapter(ArrayList()) + loadingPanel?.visibility = View.GONE + gsr_no_reservations?.visibility = View.VISIBLE + } else { + internetConnectionGSRReservations?.visibility = View.GONE + } // get email and session id from shared preferences - val sp = PreferenceManager.getDefaultSharedPreferences(mActivity) - val sessionID = sp.getString(getString(R.string.huntsmanGSR_SessionID), "") - val email = sp.getString(getString(R.string.email_address), "") - OAuth2NetworkManager(mActivity).getAccessToken() - val token = "Bearer " + sp.getString(getString(R.string.access_token), "") val labs = MainActivity.studentLifeInstance - labs.getGsrReservations(token).subscribe({ reservations -> - mActivity.runOnUiThread { - gsr_reservations_rv?.adapter = GsrReservationsAdapter(ArrayList(reservations)) - loadingPanel?.visibility = View.GONE - if (reservations.size > 0) { - gsr_no_reservations?.visibility = View.GONE - } else { + + OAuth2NetworkManager(mActivity).getAccessToken { + val sp = PreferenceManager.getDefaultSharedPreferences(mActivity) + val sessionID = sp.getString(getString(R.string.huntsmanGSR_SessionID), "") + val email = sp.getString(getString(R.string.email_address), "") + val token = sp.getString(getString(R.string.access_token), "") + labs.getGsrReservations("Bearer $token").subscribe({ reservations -> + mActivity.runOnUiThread { + gsr_reservations_rv?.adapter = GsrReservationsAdapter(ArrayList(reservations)) + loadingPanel?.visibility = View.GONE + if (reservations.size > 0) { + gsr_no_reservations?.visibility = View.GONE + } else { + gsr_no_reservations?.visibility = View.VISIBLE + } + // stop refreshing + gsr_reservations_refresh_layout?.isRefreshing = false + } + }, { throwable -> + mActivity.runOnUiThread { + Log.e("GsrReservationsFragment", "Error getting reservations", throwable) + gsr_reservations_rv?.adapter = GsrReservationsAdapter(ArrayList()) + throwable.printStackTrace() + loadingPanel?.visibility = View.GONE gsr_no_reservations?.visibility = View.VISIBLE + gsr_reservations_refresh_layout?.isRefreshing = false } - // stop refreshing - gsr_reservations_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("GsrReservationsFragment", "Error getting reservations", throwable); - throwable.printStackTrace() - loadingPanel?.visibility = View.GONE - gsr_no_reservations?.visibility = View.VISIBLE - gsr_reservations_refresh_layout?.isRefreshing = false - } - }) + }) + } } private val broadcastReceiver = object: BroadcastReceiver() { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrTabbedFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrTabbedFragment.kt index 35c570b0b..e29891263 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrTabbedFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/GsrTabbedFragment.kt @@ -1,8 +1,6 @@ package com.pennapps.labs.pennmobile -import android.os.Build import android.os.Bundle -import android.util.Log import com.google.android.material.tabs.TabLayout import androidx.fragment.app.Fragment import androidx.viewpager.widget.ViewPager @@ -12,41 +10,34 @@ import android.view.ViewGroup import androidx.coordinatorlayout.widget.CoordinatorLayout import com.pennapps.labs.pennmobile.components.collapsingtoolbar.ToolbarBehavior import com.pennapps.labs.pennmobile.utils.Utils -import kotlinx.android.synthetic.main.fragment_dining.* -import kotlinx.android.synthetic.main.fragment_dining.view.* -import androidx.annotation.RequiresApi import kotlinx.android.synthetic.main.fragment_gsr_tabs.* import kotlinx.android.synthetic.main.fragment_gsr_tabs.view.* import kotlinx.android.synthetic.main.fragment_gsr_tabs.view.appbar_home import kotlinx.android.synthetic.main.fragment_gsr_tabs.view.date_view import kotlinx.android.synthetic.main.include_main.* -import kotlinx.android.synthetic.main.fragment_dining_holder.view.title_view as title_view1 class GsrTabbedFragment : Fragment() { lateinit var viewPager: ViewPager lateinit var tabLayout: TabLayout - @RequiresApi(Build.VERSION_CODES.M) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { // Inflate the layout for this fragment val view = inflater.inflate(R.layout.fragment_gsr_tabs, container, false) - val fragmentAdapter = GsrPagerAdapter(childFragmentManager) - viewPager = view.gsr_viewpager - viewPager.adapter = fragmentAdapter - initAppBar(view) - tabLayout = view.gsr_tab_layout - tabLayout.setupWithViewPager(viewPager) return view } - @RequiresApi(Build.VERSION_CODES.M) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + val fragmentAdapter = activity?.supportFragmentManager?.let { GsrPagerAdapter(it) } + viewPager = view.gsr_viewpager + viewPager.adapter = fragmentAdapter + tabLayout = view.gsr_tab_layout + tabLayout.setupWithViewPager(viewPager) //displays banner if not connected if (!isOnline(context)) { internetConnectionGSR?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) @@ -64,9 +55,7 @@ class GsrTabbedFragment : Fragment() { } private fun initAppBar(view: View) { - if (Build.VERSION.SDK_INT > 16) { - (view.appbar_home.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() - } + (view.appbar_home.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() view.title_view.text = getString(R.string.gsr) view.date_view.text = Utils.getCurrentSystemTime() } diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HomeFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HomeFragment.kt index 010bac4ed..0855a2450 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HomeFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HomeFragment.kt @@ -12,7 +12,6 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast import androidx.annotation.RequiresApi import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.fragment.app.Fragment @@ -22,11 +21,12 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.google.firebase.analytics.FirebaseAnalytics import com.pennapps.labs.pennmobile.adapters.HomeAdapter import com.pennapps.labs.pennmobile.api.OAuth2NetworkManager -import com.pennapps.labs.pennmobile.classes.DiningHallPreference import com.pennapps.labs.pennmobile.classes.HomeCell import com.pennapps.labs.pennmobile.classes.HomeCellInfo +import com.pennapps.labs.pennmobile.classes.PollCell import com.pennapps.labs.pennmobile.components.collapsingtoolbar.ToolbarBehavior import com.pennapps.labs.pennmobile.utils.Utils +import com.pennapps.labs.pennmobile.utils.Utils.getSha256Hash import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.view.* import kotlinx.android.synthetic.main.include_main.* @@ -57,7 +57,6 @@ class HomeFragment : Fragment() { FirebaseAnalytics.getInstance(mActivity).logEvent(FirebaseAnalytics.Event.VIEW_ITEM, bundle) } - @RequiresApi(Build.VERSION_CODES.M) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -73,22 +72,16 @@ class HomeFragment : Fragment() { view.home_refresh_layout .setOnRefreshListener { getHomePage() } - getHomePage() initAppBar(view) return view } - @RequiresApi(Build.VERSION_CODES.M) - private fun getHomePage() { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + getHomePage() + } - // get session id from shared preferences - val sp = sharedPreferences - val sessionID = sp.getString(getString(R.string.huntsmanGSR_SessionID), "") - val accountID = sp.getString(getString(R.string.accountID), "") - val deviceID = OAuth2NetworkManager(mActivity).getDeviceId() - OAuth2NetworkManager(mActivity).getAccessToken() - val bearerToken = "Bearer " + sp.getString(getString(R.string.access_token), "").toString() - Log.i("HomeFragment", bearerToken) + private fun getHomePage() { //displays banner if not connected if (!isOnline(context)) { @@ -96,6 +89,9 @@ class HomeFragment : Fragment() { internetConnection_message?.text = getString(R.string.internet_error) home_cells_rv?.setPadding(0, 90, 0, 0) internetConnectionHome?.visibility = View.VISIBLE + home_refresh_layout?.isRefreshing = false + loadingPanel?.visibility = View.GONE + return } else { internetConnectionHome?.visibility = View.GONE home_cells_rv?.setPadding(0, 0, 0, 0) @@ -104,213 +100,320 @@ class HomeFragment : Fragment() { // get API data val homepageCells = mutableListOf() - for (i in 1..5) { + for (i in 1..7) { homepageCells.add(HomeCell()) } + // number of cells loaded + var loaded = 0 + val studentLife = MainActivity.studentLifeInstance - if (bearerToken != "Bearer ") { - - studentLife.getNews().subscribe({ article -> - mActivity.runOnUiThread { - val newsCell = HomeCell() - newsCell.info = HomeCellInfo() - newsCell.info?.article = article - newsCell.type = "news" - homepageCells.set(1, newsCell) - home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) - loadingPanel?.visibility = View.GONE - home_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("Home", "Could not load news", throwable) - throwable.printStackTrace() - Toast.makeText(mActivity, "Could not load news", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - internetConnectionHome?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message?.text = getString(R.string.internet_error) - internetConnectionHome?.visibility = View.VISIBLE - home_refresh_layout?.isRefreshing = false - } - }) - - studentLife.getDiningPreferences(bearerToken).subscribe({ preferences -> - mActivity.runOnUiThread { - val list = preferences.preferences - val venues = mutableListOf() - val diningCell = HomeCell() - diningCell.type = "dining" - val diningCellInfo = HomeCellInfo() - if(list?.isEmpty() == true ) { - venues.add(593) - venues.add(1442) - venues.add(636) - } else { - list?.forEach({ - it?.id?.let { it1 -> venues.add(it1) } - }) + OAuth2NetworkManager(mActivity).getAccessToken { + val sp = sharedPreferences + val deviceID = OAuth2NetworkManager(mActivity).getDeviceId() + val bearerToken = "Bearer " + sp.getString(getString(R.string.access_token), "").toString() + Log.i("HomeFragment", bearerToken) + if (bearerToken != "Bearer ") { + val totalCells = 6 + + val idHash = getSha256Hash(deviceID) + studentLife.browsePolls(bearerToken, idHash).subscribe({ poll -> + if (poll.size > 0) { + mActivity.runOnUiThread { + val pollCell = PollCell(poll[0]) + pollCell.poll.options.forEach { pollCell.poll.totalVotes += it.voteCount } + homepageCells[0] = pollCell + } + } + loaded++ + + Log.i("HomeFragment", "polls $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + }, { throwable -> + Log.e("Poll", "Error retrieving polls", throwable) + loaded++ + + Log.i("HomeFragment", "polls $loaded") + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false } - diningCellInfo.venues = venues - diningCell.info = diningCellInfo - homepageCells.set(2, diningCell) - home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) - loadingPanel?.visibility = View.GONE - internetConnectionHome?.visibility = View.GONE - home_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("Home", "Could not load Home page", throwable) - throwable.printStackTrace() - Toast.makeText(mActivity, "Could not load Home page", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - internetConnectionHome?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message?.text = getString(R.string.internet_error) - internetConnectionHome?.visibility = View.VISIBLE - home_refresh_layout?.isRefreshing = false - } - }) - - studentLife.getCalendar().subscribe({ events -> - mActivity.runOnUiThread { - val calendar = HomeCell() - calendar.type = "calendar" - calendar.events = events - homepageCells.set(0, calendar) - val gsrBookingCell = HomeCell() - gsrBookingCell.type = "gsr_booking" - gsrBookingCell.buildings = arrayListOf("Huntsman Hall", "Weigle") - homepageCells.set(3, gsrBookingCell) - home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) - loadingPanel?.visibility = View.GONE - home_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("Home", "Could not load calendar", throwable) - throwable.printStackTrace() - Toast.makeText(mActivity, "Could not load calendar", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - internetConnectionHome?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message?.text = getString(R.string.internet_error) - internetConnectionHome?.visibility = View.VISIBLE - home_refresh_layout?.isRefreshing = false - } - }) - - studentLife.getLaundryPref(bearerToken).subscribe({ preferences -> - mActivity.runOnUiThread { - val venues = mutableListOf() - val laundryCell = HomeCell() - laundryCell.type = "laundry" - val laundryCellInfo = HomeCellInfo() - if(preferences?.isEmpty() == false ) { - laundryCellInfo.roomId = preferences[0] + }) + + studentLife.news.subscribe({ article -> + mActivity.runOnUiThread { + val newsCell = HomeCell() + newsCell.info = HomeCellInfo() + newsCell.info?.article = article + newsCell.type = "news" + homepageCells[3] = newsCell + + loaded++ + Log.i("HomeFragment", "news $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }, { throwable -> + mActivity.runOnUiThread { + Log.e("Home", "Could not load news", throwable) + throwable.printStackTrace() + + loaded++ + Log.i("HomeFragment", "news $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }) + + studentLife.getDiningPreferences(bearerToken).subscribe({ preferences -> + mActivity.runOnUiThread { + val list = preferences.preferences + val venues = mutableListOf() + val diningCell = HomeCell() + diningCell.type = "dining" + val diningCellInfo = HomeCellInfo() + if (list?.isEmpty() == true) { + venues.add(593) + venues.add(1442) + venues.add(636) + } else { + list?.forEach({ + it.id?.let { it1 -> venues.add(it1) } + }) + + } + diningCellInfo.venues = venues + diningCell.info = diningCellInfo + homepageCells[4] = diningCell + + loaded++ + Log.i("HomeFragment", "dining $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }, { throwable -> + mActivity.runOnUiThread { + Log.e("Home", "Could not load Dining", throwable) + throwable.printStackTrace() + + loaded++ + Log.i("HomeFragment", "dining $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }) + + studentLife.calendar.subscribe({ events -> + mActivity.runOnUiThread { + val calendar = HomeCell() + calendar.type = "calendar" + calendar.events = events + homepageCells[1] = calendar + val gsrBookingCell = HomeCell() + gsrBookingCell.type = "gsr_booking" + gsrBookingCell.buildings = arrayListOf("Huntsman Hall", "Weigle") + homepageCells[5] = gsrBookingCell + loaded++ + Log.i("HomeFragment", "calendar $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }, { throwable -> + mActivity.runOnUiThread { + Log.e("Home", "Could not load calendar", throwable) + throwable.printStackTrace() + loaded++ + Log.i("HomeFragment", "calendar $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }) + + studentLife.getLaundryPref(bearerToken).subscribe({ preferences -> + mActivity.runOnUiThread { + val venues = mutableListOf() + val laundryCell = HomeCell() + laundryCell.type = "laundry" + val laundryCellInfo = HomeCellInfo() + if (preferences?.isEmpty() == false) { + laundryCellInfo.roomId = preferences[0] + } + laundryCell.info = laundryCellInfo + homepageCells[6] = laundryCell + loaded++ + Log.i("HomeFragment", "laundry $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }, { throwable -> + mActivity.runOnUiThread { + Log.e("Home", "Could not load laundry", throwable) + throwable.printStackTrace() + loaded++ + Log.i("HomeFragment", "laundry $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }) + + studentLife.validPostsList(bearerToken).subscribe({ post -> + if (post.size >= 1) { //there exists a post + mActivity.runOnUiThread { + val postCell = HomeCell() + postCell.info = HomeCellInfo() + postCell.type = "post" + postCell.info?.post = post[0] + homepageCells[2] = postCell + } } - laundryCell.info = laundryCellInfo - homepageCells.set(4, laundryCell) - home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) - loadingPanel?.visibility = View.GONE - internetConnectionHome?.visibility = View.GONE - home_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("Home", "Could not load laundry", throwable) - throwable.printStackTrace() - Toast.makeText(mActivity, "Could not load home laundry", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - internetConnectionHome?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message?.text = getString(R.string.internet_error) - internetConnectionHome?.visibility = View.VISIBLE - home_refresh_layout?.isRefreshing = false - } - }) - - /*studentLife.getHomePage(bearerToken).subscribe({ cells -> - mActivity.runOnUiThread { - val gsrBookingCell = HomeCell() - gsrBookingCell.type = "gsr_booking" - gsrBookingCell.buildings = arrayListOf("Huntsman Hall", "Weigle") - cells?.add(cells.size - 1, gsrBookingCell) - homepageCells.addAll(homepageCells.size, cells) - home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) - //(home_cells_rv?.adapter as HomeAdapter).notifyDataSetChanged() - loadingPanel?.visibility = View.GONE - home_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("Home", "Could not load Home page", throwable) - throwable.printStackTrace() - Toast.makeText(mActivity, "Could not load Home page", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - internetConnectionHome?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message?.text = getString(R.string.internet_error) - internetConnectionHome?.visibility = View.VISIBLE - home_refresh_layout?.isRefreshing = false - } - }) */ - } else { - studentLife.getCalendar().subscribe({ events -> - mActivity.runOnUiThread { - val calendar = HomeCell() - calendar.type = "calendar" - calendar.events = events - homepageCells.add(0, calendar) - home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) - loadingPanel?.visibility = View.GONE - home_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("Home", "Could not load Home page", throwable) - throwable.printStackTrace() - Toast.makeText(mActivity, "Could not load Home page", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - internetConnectionHome?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message?.text = getString(R.string.internet_error) - internetConnectionHome?.visibility = View.VISIBLE - home_refresh_layout?.isRefreshing = false - } - }) - - studentLife.getNews().subscribe({ article -> - mActivity.runOnUiThread { - val newsCell = HomeCell() - newsCell.info = HomeCellInfo() - newsCell.info?.article = article - newsCell.type = "news" - homepageCells.add(homepageCells.size, newsCell) - val gsrBookingCell = HomeCell() - gsrBookingCell.type = "gsr_booking" - gsrBookingCell.buildings = arrayListOf("Huntsman Hall", "Weigle") - homepageCells.add(homepageCells.size, gsrBookingCell) - home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) - loadingPanel?.visibility = View.GONE - home_refresh_layout?.isRefreshing = false - } - }, { throwable -> - mActivity.runOnUiThread { - Log.e("Home", "Could not load Home page", throwable) - throwable.printStackTrace() - Toast.makeText(mActivity, "Could not load Home page", Toast.LENGTH_LONG).show() - loadingPanel?.visibility = View.GONE - internetConnectionHome?.setBackgroundColor(resources.getColor(R.color.darkRedBackground)) - internetConnection_message?.text = getString(R.string.internet_error) - internetConnectionHome?.visibility = View.VISIBLE - home_refresh_layout?.isRefreshing = false - } - }) - } + loaded++ + Log.i("HomeFragment", "posts $loaded") + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + + }, { throwable -> + mActivity.runOnUiThread { + Log.e("Home", "Could not load posts", throwable) + throwable.printStackTrace() + loaded++ + Log.i("HomeFragment", "posts $loaded") + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + + }) + } else { + val totalCells = 2 + + studentLife.calendar.subscribe({ events -> + mActivity.runOnUiThread { + val calendar = HomeCell() + calendar.type = "calendar" + calendar.events = events + homepageCells.add(0, calendar) + loaded++ + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }, { throwable -> + mActivity.runOnUiThread { + Log.e("Home", "Could not load Home page", throwable) + throwable.printStackTrace() + loaded++ + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }) + + studentLife.news.subscribe({ article -> + mActivity.runOnUiThread { + val newsCell = HomeCell() + newsCell.info = HomeCellInfo() + newsCell.info?.article = article + newsCell.type = "news" + homepageCells.add(homepageCells.size, newsCell) + val gsrBookingCell = HomeCell() + gsrBookingCell.type = "gsr_booking" + gsrBookingCell.buildings = arrayListOf("Huntsman Hall", "Weigle") + homepageCells.add(homepageCells.size, gsrBookingCell) + loaded++ + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }, { throwable -> + mActivity.runOnUiThread { + Log.e("Home", "Could not load Home page", throwable) + throwable.printStackTrace() + loaded++ + + if (loaded == totalCells) { + home_cells_rv?.adapter = HomeAdapter(ArrayList(homepageCells)) + loadingPanel?.visibility = View.GONE + internetConnectionHome?.visibility = View.GONE + home_refresh_layout?.isRefreshing = false + } + } + }) + } + } } private val broadcastReceiver = object : BroadcastReceiver() { - @RequiresApi(Build.VERSION_CODES.M) override fun onReceive(context: Context?, intent: Intent?) { getHomePage() } @@ -325,20 +428,11 @@ class HomeFragment : Fragment() { if (initials != null && initials.isNotEmpty()) { this.initials.text = initials } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - this.profile_background.setImageDrawable( - resources.getDrawable - (R.drawable.ic_guest_avatar, context?.theme)) - } else { - @Suppress("DEPRECATION") - this.profile_background.setImageDrawable( - resources.getDrawable - (R.drawable.ic_guest_avatar)) - } - } - if (Build.VERSION.SDK_INT > 17) { - mActivity.setSelectedTab(MainActivity.HOME) + this.profile_background.setImageDrawable( + resources.getDrawable + (R.drawable.ic_guest_avatar, context?.theme)) } + mActivity.setSelectedTab(MainActivity.HOME) mActivity.showBottomBar() } @@ -359,10 +453,8 @@ class HomeFragment : Fragment() { } ?: run { view.date_view.text = Utils.getCurrentSystemTime() } - if (Build.VERSION.SDK_INT > 16) { - (view.appbar_home.layoutParams - as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() - } + (view.appbar_home.layoutParams + as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() view.profile.setOnClickListener { //TODO: Account Settings } @@ -373,9 +465,14 @@ class HomeFragment : Fragment() { */ @Suppress("DEPRECATION") private fun displaySnack(view: View, text: String) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - (view as ViewGroup).showSneakerToast(message = text, doOnRetry = { }, sneakerColor = R.color.sneakerBlurColorOverlay) - } + (view as ViewGroup).showSneakerToast(message = text, doOnRetry = { }, sneakerColor = R.color.sneakerBlurColorOverlay) } + enum class Cells { + POLLS, NEWS, DINING, CALENDAR, LAUNDRY, POSTS + } + + + + } \ No newline at end of file diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HuntsmanGSRLogin.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HuntsmanGSRLogin.kt index 702b72683..5d9ab1be3 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HuntsmanGSRLogin.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/HuntsmanGSRLogin.kt @@ -13,6 +13,7 @@ import android.webkit.CookieManager import android.webkit.WebView import android.webkit.WebViewClient import android.widget.Toast +import com.pennapps.labs.pennmobile.api.OAuth2NetworkManager import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.GSRBookingResult import kotlinx.android.synthetic.main.fragment_huntsman_gsrlogin.* @@ -102,7 +103,9 @@ class HuntsmanGSRLogin : Fragment() { // performs POST request and redirects user to GSR booking fragment private fun bookHuntsmanGSR(bearerToken : String, sessionID : String) { - mStudentLife.bookGSR( + OAuth2NetworkManager(activity as MainActivity).getAccessToken { + + mStudentLife.bookGSR( //Passing the values bearerToken, startTime, @@ -116,11 +119,12 @@ class HuntsmanGSRLogin : Fragment() { override fun success(result: GSRBookingResult?, response: Response?) { //Display the output as a toast if (result?.getResults() == true) { - Toast.makeText(mActivity, "GSR successfully booked", Toast.LENGTH_LONG).show() - } - else { + Toast.makeText(mActivity, "GSR successfully booked", Toast.LENGTH_LONG) + .show() + } else { Log.e("HuntsmanGSRLogin", "GSR booking failed: " + result?.getError()) - Toast.makeText(mActivity, "GSR booking failed", Toast.LENGTH_LONG).show() + Toast.makeText(mActivity, "GSR booking failed", Toast.LENGTH_LONG) + .show() val sp = PreferenceManager.getDefaultSharedPreferences(mActivity) val editor = sp.edit() editor.remove(getString(R.string.huntsmanGSR_SessionID)) @@ -130,9 +134,9 @@ class HuntsmanGSRLogin : Fragment() { val gsrFragment = GsrTabbedFragment() val fragmentManager = mActivity.supportFragmentManager fragmentManager.beginTransaction() - .replace(R.id.content_frame, gsrFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .commit() + .replace(R.id.content_frame, gsrFragment) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .commit() } override fun failure(error: RetrofitError?) { @@ -147,12 +151,13 @@ class HuntsmanGSRLogin : Fragment() { val gsrFragment = GsrTabbedFragment() val fragmentManager = mActivity.supportFragmentManager fragmentManager.beginTransaction() - .replace(R.id.content_frame, gsrFragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .commit() + .replace(R.id.content_frame, gsrFragment) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .commit() } } - ) + ) + } } companion object { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryBroadcastReceiver.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryBroadcastReceiver.kt index e08b11224..9bec35717 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryBroadcastReceiver.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryBroadcastReceiver.kt @@ -7,7 +7,6 @@ import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat @@ -31,32 +30,22 @@ class LaundryBroadcastReceiver : BroadcastReceiver() { // build notification val mBuilder: NotificationCompat.Builder - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channelName = "Laundry Alarm" - val channelId = "pennmobile_laundry_alarm" - val description = "Alarm for laundry machine availability" - val importance = NotificationManager.IMPORTANCE_DEFAULT - val channel = NotificationChannel(channelId, channelName, importance) - channel.description = description - channel.enableLights(true) - channel.lightColor = ContextCompat.getColor(context, R.color.color_primary) - notificationManager.createNotificationChannel(channel) - mBuilder = NotificationCompat.Builder(context, channel.id) - .setSmallIcon(R.drawable.ic_bottom_nav_laundry_grey) - .setContentTitle(context.getString(R.string.app_name)) - .setContentText(builder) - } else { - val channelId = "pennmobile_laundry_alarm" - mBuilder = NotificationCompat.Builder(context, channelId) - .setSmallIcon(R.drawable.ic_bottom_nav_laundry_grey) - .setContentTitle(context.getString(R.string.app_name)) - .setContentText(builder) - } + val channelName = "Laundry Alarm" + val channelId = "pennmobile_laundry_alarm" + val description = "Alarm for laundry machine availability" + val importance = NotificationManager.IMPORTANCE_DEFAULT + val channel = NotificationChannel(channelId, channelName, importance) + channel.description = description + channel.enableLights(true) + channel.lightColor = ContextCompat.getColor(context, R.color.color_primary) + notificationManager.createNotificationChannel(channel) + mBuilder = NotificationCompat.Builder(context, channel.id) + .setSmallIcon(R.drawable.ic_bottom_nav_laundry_grey) + .setContentTitle(context.getString(R.string.app_name)) + .setContentText(builder) mBuilder.setAutoCancel(true) mBuilder.setDefaults(Notification.DEFAULT_SOUND or Notification.DEFAULT_VIBRATE) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - mBuilder.color = ContextCompat.getColor(context, R.color.color_primary) - } + mBuilder.color = ContextCompat.getColor(context, R.color.color_primary) // intent to go to main activity val laundryIntent = Intent(context, MainActivity::class.java) diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryFragment.kt index ee8204cc2..845b3ef0c 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundryFragment.kt @@ -2,12 +2,10 @@ package com.pennapps.labs.pennmobile import android.content.Context import android.content.SharedPreferences -import android.os.Build import android.os.Bundle import android.preference.PreferenceManager import android.util.Log import android.view.* -import androidx.annotation.RequiresApi import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction @@ -64,7 +62,6 @@ class LaundryFragment : Fragment() { FirebaseAnalytics.getInstance(mContext).logEvent(FirebaseAnalytics.Event.VIEW_ITEM, bundle) } - @RequiresApi(Build.VERSION_CODES.M) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_laundry, container, false) @@ -95,10 +92,27 @@ class LaundryFragment : Fragment() { return view } - private fun initAppBar(view: View) { - if (Build.VERSION.SDK_INT > 16) { - (view.appbar_home.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mActivity.removeTabs() + mActivity.toolbar.visibility = View.GONE + numRooms = sp?.getInt(mContext.getString(R.string.num_rooms_pref), 100) ?: 0 + + // get num rooms to display + count = 0 + for (i in 0 until numRooms) { + if (sp?.getBoolean(i.toString(), false) == true) { + count += 1 + } } + mActivity.setTitle(R.string.laundry) + mActivity.setSelectedTab(MainActivity.LAUNDRY) + loadingPanel?.visibility = View.VISIBLE + updateRooms() + } + + private fun initAppBar(view: View) { + (view.appbar_home.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior() view.title_view.text = getString(R.string.laundry) view.date_view.text = Utils.getCurrentSystemTime() view.laundry_preferences.setOnClickListener { @@ -132,23 +146,6 @@ class LaundryFragment : Fragment() { override fun onResume() { super.onResume() - mActivity.removeTabs() - mActivity.toolbar.visibility = View.GONE - numRooms = sp?.getInt(mContext.getString(R.string.num_rooms_pref), 100) ?: 0 - - // get num rooms to display - count = 0 - for (i in 0 until numRooms) { - if (sp?.getBoolean(i.toString(), false) == true) { - count += 1 - } - } - mActivity.setTitle(R.string.laundry) - if (Build.VERSION.SDK_INT > 17){ - mActivity.setSelectedTab(MainActivity.LAUNDRY) - } - loadingPanel?.visibility = View.VISIBLE - updateRooms() } private fun updateRooms() { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundrySettingsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundrySettingsFragment.kt index b0b459148..5391bc01b 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundrySettingsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LaundrySettingsFragment.kt @@ -2,7 +2,6 @@ package com.pennapps.labs.pennmobile import android.content.Context import android.content.SharedPreferences -import android.os.Build import android.os.Bundle import android.view.* import android.widget.Button @@ -41,6 +40,7 @@ class LaundrySettingsFragment : Fragment() { mActivity.closeKeyboard() setHasOptionsMenu(true) mActivity.toolbar.visibility = View.VISIBLE + mActivity.expandable_bottom_bar.visibility = View.GONE val bundle = Bundle() bundle.putString(FirebaseAnalytics.Param.ITEM_ID, "12") @@ -98,7 +98,7 @@ class LaundrySettingsFragment : Fragment() { var roomList: MutableList = ArrayList() // if hall name already exists, get the list of rooms and add to that - val hallName = rooms[i].location ?: "" + var hallName = rooms[i].location ?: "" if (hallList.contains(hallName)) { roomList = hashMap[hallName] as MutableList @@ -115,6 +115,11 @@ class LaundrySettingsFragment : Fragment() { } } + // name formatting for consistency + if (hallName == "Lauder College House") { + hallName = "Lauder" + } + // add the hall name to the list hallList.add(hallName) hashMap[hallName] = roomList @@ -145,9 +150,7 @@ class LaundrySettingsFragment : Fragment() { super.onResume() mActivity.removeTabs() mActivity.setTitle(R.string.laundry) - if (Build.VERSION.SDK_INT > 17){ - mActivity.setSelectedTab(MainActivity.LAUNDRY) - } + mActivity.setSelectedTab(MainActivity.LAUNDRY) } override fun onDestroyView() { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginFragment.kt index 6002be3b8..ef7c14742 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginFragment.kt @@ -1,7 +1,5 @@ package com.pennapps.labs.pennmobile -import android.content.res.Configuration -import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -31,10 +29,10 @@ class LoginFragment : Fragment() { val v = inflater.inflate(R.layout.fragment_login, container, false) val fragmentManager = mActivity.supportFragmentManager - var gif = R.drawable.login_background - if (Build.VERSION.SDK_INT > 28 && (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) { - //gif = R.drawable.login_background_dark - } + val gif = R.drawable.login_background +// if (Build.VERSION.SDK_INT > 28 && (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) { +// gif = R.drawable.login_background_dark +// } Glide.with(this).asGif().load(gif).listener(object : RequestListener { override fun onLoadFailed(e: GlideException?, model: Any?, target: com.bumptech.glide.request.target.Target?, isFirstResource: Boolean): Boolean { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginWebviewFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginWebviewFragment.kt index 1cf6d73e5..5f0b79cca 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginWebviewFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/LoginWebviewFragment.kt @@ -1,7 +1,6 @@ package com.pennapps.labs.pennmobile import android.content.SharedPreferences -import android.os.Build import android.os.Bundle import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties @@ -98,49 +97,43 @@ class LoginWebviewFragment : Fragment() { } private fun encryptPassword(password: String) { - if (Build.VERSION.SDK_INT >= 26) { - var secretKey = createSecretKey() as SecretKey - var cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7) - cipher.init(Cipher.ENCRYPT_MODE, secretKey) - - var encryptionIv = cipher.iv - var passwordBytes = password.toByteArray(Charset.forName("UTF-8")) - var encryptedPasswordBytes = cipher.doFinal(passwordBytes) - var encryptedPassword = Base64.getEncoder().encodeToString(encryptedPasswordBytes) - - //save the encrypted password - val spEditor = sp.edit() - spEditor.putString("penn_password", encryptedPassword) - spEditor.apply() - spEditor.commit() - spEditor.putString("encryptionIv", Base64.getEncoder().encodeToString(encryptionIv)) - spEditor.apply() - spEditor.commit() - } + val secretKey = createSecretKey() as SecretKey + val cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7) + cipher.init(Cipher.ENCRYPT_MODE, secretKey) + + val encryptionIv = cipher.iv + val passwordBytes = password.toByteArray(Charset.forName("UTF-8")) + val encryptedPasswordBytes = cipher.doFinal(passwordBytes) + val encryptedPassword = Base64.getEncoder().encodeToString(encryptedPasswordBytes) + + //save the encrypted password + val spEditor = sp.edit() + spEditor.putString("penn_password", encryptedPassword) + spEditor.apply() + spEditor.commit() + spEditor.putString("encryptionIv", Base64.getEncoder().encodeToString(encryptionIv)) + spEditor.apply() + spEditor.commit() } private fun getDecodedPassword(): String? { - if (Build.VERSION.SDK_INT >= 26) { - var base64EncryptedPassword = sp.getString("penn_password", "null") - var base64EncryptionIv = sp.getString("encryptionIv", "null") - - var encryptionIv = Base64.getDecoder().decode(base64EncryptionIv) - var encryptedPassword = Base64.getDecoder().decode(base64EncryptedPassword) - - var keyStore = KeyStore.getInstance("AndroidKeyStore") - keyStore.load(null) - - var secretkey = keyStore.getKey("Key", null) as SecretKey - var cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + - KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7) - cipher.init(Cipher.DECRYPT_MODE, secretkey, IvParameterSpec(encryptionIv)) - - var passwordBytes = cipher.doFinal(encryptedPassword) - var password = String(passwordBytes, Charset.forName("UTF-8")) - return password - } else { - return null - } + val base64EncryptedPassword = sp.getString("penn_password", "null") + val base64EncryptionIv = sp.getString("encryptionIv", "null") + + val encryptionIv = Base64.getDecoder().decode(base64EncryptionIv) + val encryptedPassword = Base64.getDecoder().decode(base64EncryptedPassword) + + val keyStore = KeyStore.getInstance("AndroidKeyStore") + keyStore.load(null) + + val secretkey = keyStore.getKey("Key", null) as SecretKey + val cipher = Cipher.getInstance( + KeyProperties.KEY_ALGORITHM_AES + "/" + + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7 + ) + cipher.init(Cipher.DECRYPT_MODE, secretkey, IvParameterSpec(encryptionIv)) + val passwordBytes = cipher.doFinal(encryptedPassword) + return String(passwordBytes, Charset.forName("UTF-8")) } private fun saveUsername(username: String) { @@ -150,16 +143,13 @@ class LoginWebviewFragment : Fragment() { } private fun createSecretKey(): SecretKey? { - if (Build.VERSION.SDK_INT >= 23) { - val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") - keyGenerator.init(KeyGenParameterSpec.Builder("Key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(KeyProperties.BLOCK_MODE_CBC) - .setUserAuthenticationRequired(false) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) - .build()) - return keyGenerator.generateKey() - } - return null + val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") + keyGenerator.init(KeyGenParameterSpec.Builder("Key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(KeyProperties.BLOCK_MODE_CBC) + .setUserAuthenticationRequired(false) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) + .build()) + return keyGenerator.generateKey() } inner class MyWebViewClient : WebViewClient() { @@ -174,54 +164,57 @@ class LoginWebviewFragment : Fragment() { if (url.contains("callback") && url.contains("?code=")) { val urlArr = url.split("?code=").toTypedArray() val authCode = urlArr[urlArr.size - 1] + Log.d("AuthCode", authCode) + Log.d("ClientId", clientID) + Log.d("RedirectURI", redirectUri) + Log.d("CodeVerifier", codeVerifier) initiateAuthentication(authCode) } if (url.contains("weblogin") && url.contains("pennkey")) { - if (Build.VERSION.SDK_INT >= 19) { - webView.evaluateJavascript("document.getElementById('pennname').value;", ValueCallback { s -> - if (s != null || s != "null") { - saveUsername(s) - } - }) - webView.evaluateJavascript("document.getElementById('password').value;", ValueCallback { s -> - if (s != null || s != "null") { - encryptPassword(s) - } - }) - } + webView.evaluateJavascript("document.getElementById('pennname').value;", ValueCallback { s -> + if (s != null || s != "null") { + saveUsername(s) + } + }) + webView.evaluateJavascript("document.getElementById('password').value;", ValueCallback { s -> + if (s != null || s != "null") { + encryptPassword(s) + } + }) } return super.shouldOverrideUrlLoading(view, url) } } private fun initiateAuthentication(authCode: String) { - mPlatform?.getAccessToken(authCode, - "authorization_code", clientID, redirectUri, codeVerifier, - object : Callback { - - override fun success(t: AccessTokenResponse?, response: Response?) { - if (response?.status == 200) { - val accessToken = t?.accessToken - val editor = sp.edit() - editor.putString(getString(R.string.access_token), accessToken) - editor.putString(getString(R.string.refresh_token), t?.refreshToken) - editor.putString(getString(R.string.expires_in), t?.expiresIn) - val calendar = Calendar.getInstance() - calendar.time = Date() - val expiresInInt = t?.expiresIn!!.toInt() - val date = Date(System.currentTimeMillis().plus(expiresInInt)) //or simply new Date(); - editor.putLong(getString(R.string.token_generated), date.time) - editor.apply() - getUser(accessToken) - } - } + mStudentLife.getAccessToken(authCode, - override fun failure(error: RetrofitError) { - Log.e("Accounts", "Error fetching access token $error", error) - Toast.makeText(mActivity, "Error logging in", Toast.LENGTH_SHORT).show() - mActivity.startLoginFragment() + "authorization_code", clientID, redirectUri, codeVerifier, + object : Callback { + + override fun success(t: AccessTokenResponse?, response: Response?) { + if (response?.status == 200) { + val accessToken = t?.accessToken + val editor = sp.edit() + editor.putString(getString(R.string.access_token), accessToken) + editor.putString(getString(R.string.refresh_token), t?.refreshToken) + editor.putString(getString(R.string.expires_in), t?.expiresIn) + + val expiresInInt = t?.expiresIn!!.toInt() * 1000 + Log.i("LoginWebview", "Expires In: $expiresInInt") + val currentTime = Calendar.getInstance().timeInMillis + editor.putLong(getString(R.string.token_expires_at), currentTime + expiresInInt) + editor.apply() + getUser(accessToken) } - }) + } + + override fun failure(error: RetrofitError) { + Log.e("Accounts", "Error fetching access token $error", error) + Toast.makeText(mActivity, "Error logging in", Toast.LENGTH_SHORT).show() + mActivity.startLoginFragment() + } + }) } private fun getUser(accessToken: String?) { @@ -257,6 +250,7 @@ class LoginWebviewFragment : Fragment() { } private fun saveAccount(account: Account, pennkey: String, accessToken: String?) { + // warning this network call is unsafe mStudentLife.saveAccount("Bearer $accessToken", pennkey, account, object : Callback { override fun success(t: SaveAccountResponse?, response: Response?) { @@ -282,13 +276,8 @@ class LoginWebviewFragment : Fragment() { val byteArr = md.digest(codeVerifier.toByteArray()) // Base-64 encode - var codeChallenge = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + var codeChallenge = Base64.getEncoder().encodeToString(byteArr) - } else { - String( - android.util.Base64.encode(byteArr, android.util.Base64.DEFAULT), - Charsets.UTF_8) - } // Replace characters to make it web safe codeChallenge = codeChallenge.replace("=", "") @@ -297,4 +286,4 @@ class LoginWebviewFragment : Fragment() { return codeChallenge } -} \ No newline at end of file +} diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MainActivity.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MainActivity.kt index 39ed9dd14..b89e7712c 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MainActivity.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MainActivity.kt @@ -19,14 +19,13 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager +import android.webkit.CookieManager import android.widget.TextView import android.widget.Toast -import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils -import androidx.core.view.marginBottom import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter @@ -37,40 +36,38 @@ import com.google.android.material.appbar.AppBarLayout import com.google.android.material.tabs.TabLayout import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken -import com.pennapps.labs.pennmobile.api.StudentLife -import com.pennapps.labs.pennmobile.api.OAuth2NetworkManager +import com.pennapps.labs.pennmobile.adapters.MainPagerAdapter import com.pennapps.labs.pennmobile.api.CampusExpress +import com.pennapps.labs.pennmobile.api.OAuth2NetworkManager import com.pennapps.labs.pennmobile.api.Platform import com.pennapps.labs.pennmobile.api.Serializer.* +import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.* -import com.pennapps.labs.pennmobile.components.floatingbottombar.ExpandableBottomBarMenuItem import com.pennapps.labs.pennmobile.components.sneaker.Sneaker -import com.pennapps.labs.pennmobile.more.MoreFragment import com.pennapps.labs.pennmobile.utils.Utils +import com.squareup.okhttp.OkHttpClient import eightbitlab.com.blurview.RenderScriptBlur import kotlinx.android.synthetic.main.custom_sneaker_view.view.* import kotlinx.android.synthetic.main.include_main.* +import kotlinx.coroutines.sync.Mutex import retrofit.RestAdapter import retrofit.android.AndroidLog +import retrofit.client.OkClient import retrofit.converter.GsonConverter +import java.util.concurrent.TimeUnit class MainActivity : AppCompatActivity() { private var tabShowed = false private lateinit var fragmentManager: FragmentManager private lateinit var mSharedPrefs: SharedPreferences + val tokenMutex = Mutex() + override fun onCreate(savedInstanceState: Bundle?) { setTheme(R.style.AppTheme) if (Build.VERSION.SDK_INT > 28) { setTheme(R.style.DarkModeApi29) } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - val alert = AlertDialog.Builder(this) - alert.setTitle("Android version") - alert.setMessage("You are running an older version of Android. Features may be limited") - alert.setPositiveButton("OK", null) - alert.show() - } super.onCreate(savedInstanceState) if (applicationContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) { @@ -79,35 +76,18 @@ class MainActivity : AppCompatActivity() { setContentView(R.layout.activity_main) Utils.getCurrentSystemTime() - //tabBarView = findViewById(R.id.bottom_navigation) - // toolbar = findViewById(R.id.toolbar) setSupportActionBar(appbar.findViewById(R.id.toolbar)) fragmentManager = supportFragmentManager supportActionBar?.setDisplayHomeAsUpEnabled(false) supportActionBar?.setHomeButtonEnabled(false) mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this) + val policy = StrictMode.ThreadPolicy.Builder().permitAll().build() StrictMode.setThreadPolicy(policy) - - expandable_bottom_bar.addItems( - ExpandableBottomBarMenuItem.Builder(this) - .addItem(HOME, R.drawable.ic_home_grey) - .textRes(R.string.floating_bottom_bar_home) - .colorRes(R.color.floating_bottom_bar_selected).create() - .addItem(DINING, R.drawable.ic_dining_grey) - .textRes(R.string.floating_bottom_bar_dining) - .colorRes(R.color.floating_bottom_bar_selected).create() - .addItem(GSR, R.drawable.ic_gsr_grey) - .textRes(R.string.floating_bottom_bar_gsr_booking) - .colorRes(R.color.floating_bottom_bar_selected).create() - .addItem(LAUNDRY, R.drawable.ic_laundry_grey) - .textRes(R.string.floating_bottom_bar_laundry) - .colorRes(R.color.floating_bottom_bar_selected).create() - .addItem(MORE, R.drawable.ic_more_grey) - .textRes(R.string.floating_bottom_bar_more) - .colorRes(R.color.floating_bottom_bar_selected).create() - .build() - ) + val mainPagerAdapter = MainPagerAdapter(fragmentManager, lifecycle) + main_view_pager?.adapter = mainPagerAdapter + main_view_pager.isUserInputEnabled = false + main_view_pager.offscreenPageLimit = 5 onExpandableBottomNavigationItemSelected() showBottomBar() supportActionBar?.setDisplayShowTitleEnabled(false) @@ -129,26 +109,26 @@ class MainActivity : AppCompatActivity() { } private fun onExpandableBottomNavigationItemSelected() { - expandable_bottom_bar.onItemSelectedListener = { _, item -> - var fragment: Fragment? = null - when (item.text as String) { - "Home" -> if (fragmentManager.backStackEntryCount > 0) { - fragment = HomeFragment() - } - "Dining" -> fragment = DiningHolderFragment() - "GSR" -> fragment = GsrTabbedFragment() - "Laundry" -> fragment = LaundryFragment() - "More" -> fragment = MoreFragment() + expandable_bottom_bar.setOnNavigationItemSelectedListener { item -> + val position = when (item.itemId) { + R.id.nav_home-> MainPagerAdapter.HOME_POSITION + R.id.nav_dining-> MainPagerAdapter.DINING_POSITION + R.id.nav_gsr-> MainPagerAdapter.GSR_POSITION + R.id.nav_laundry-> MainPagerAdapter.LAUNDRY_POSITION + R.id.nav_more-> MainPagerAdapter.MORE_POSITION + else -> MainPagerAdapter.HOME_POSITION } - fragmentTransact(fragment, true) + main_view_pager.setCurrentItem(position, false) + true } } - @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) - fun setSelectedTab(id: Int) { - expandable_bottom_bar.select(id) + fun setTab(id: Int) { + expandable_bottom_bar.selectedItemId = id } + fun setSelectedTab(id: Int) {} + fun closeKeyboard() { val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager val view = currentFocus @@ -158,24 +138,48 @@ class MainActivity : AppCompatActivity() { } fun startHomeFragment() { - OAuth2NetworkManager(this).getAccessToken() - val fragment: Fragment = HomeFragment() - fragmentManager.beginTransaction() - .replace(R.id.content_frame, fragment) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .commit() - expandable_bottom_bar.select(HOME) + for (fragment in supportFragmentManager.fragments) { + if(fragment != null) { + fragmentManager.beginTransaction().remove(fragment).commit() + } + } + main_view_pager.visibility = View.VISIBLE + val mainPagerAdapter = MainPagerAdapter(fragmentManager, lifecycle) + main_view_pager?.adapter = mainPagerAdapter + main_view_pager.isUserInputEnabled = false + main_view_pager.offscreenPageLimit = 5 expandable_bottom_bar.visibility = View.VISIBLE + setTab(HOME_ID) } fun startLoginFragment() { + + CookieManager.getInstance().removeAllCookie() + val editor = PreferenceManager.getDefaultSharedPreferences(this).edit() + editor.remove(getString(R.string.penn_password)) + editor.remove(getString(R.string.penn_user)) + editor.remove(getString(R.string.first_name)) + editor.remove(getString(R.string.last_name)) + editor.remove(getString(R.string.email_address)) + editor.remove(getString(R.string.pennkey)) + editor.remove(getString(R.string.accountID)) + editor.remove(getString(R.string.access_token)) + editor.remove(getString(R.string.guest_mode)) + editor.remove(getString(R.string.initials)) + editor.apply() + val currentFragment = fragmentManager.findFragmentById(R.id.content_frame) val fragment: Fragment = LoginFragment() - fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) - fragmentManager.beginTransaction() + + // change the fragment only if we're not already on the login fragment + if (currentFragment == null || currentFragment::class != fragment::class) { + fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) + fragmentManager.beginTransaction() .replace(R.id.content_frame, fragment) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) .commit() - expandable_bottom_bar.visibility = View.GONE + main_view_pager.visibility = View.GONE + expandable_bottom_bar.visibility = View.GONE + } } fun showErrorToast(errorMessage: Int) { @@ -210,7 +214,6 @@ class MainActivity : AppCompatActivity() { if (fragment != null) { runOnUiThread { try { - //TODO ALI COMMENT if (popBackStack) { fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) } @@ -266,6 +269,13 @@ class MainActivity : AppCompatActivity() { const val DINING = 3 const val LAUNDRY = 4 const val MORE = 5 + const val PCA = 6 + + const val HOME_ID = R.id.nav_home + const val GSR_ID = R.id.nav_gsr + const val DINING_ID = R.id.nav_dining + const val LAUNDRY_ID = R.id.nav_laundry + const val MORE_ID = R.id.nav_more private var mStudentLife: StudentLife? = null private var mPlatform: Platform? = null @@ -348,9 +358,16 @@ class MainActivity : AppCompatActivity() { gsonBuilder.registerTypeAdapter(object : TypeToken?>() {}.type, HomePageSerializer()) // gets user gsonBuilder.registerTypeAdapter(Account::class.java, UserSerializer()) + // gets posts + gsonBuilder.registerTypeAdapter(object: TypeToken?>() {}.type, PostsSerializer()) val gson = gsonBuilder.create() + val okHttpClient = OkHttpClient() + okHttpClient.setConnectTimeout(35, TimeUnit.SECONDS) // Connection timeout + okHttpClient.setReadTimeout(35, TimeUnit.SECONDS) // Read timeout + okHttpClient.setWriteTimeout(35, TimeUnit.SECONDS) // Write timeout val restAdapter = RestAdapter.Builder() .setConverter(GsonConverter(gson)) + .setClient(OkClient(okHttpClient)) .setEndpoint("https://pennmobile.org/api") .build() mStudentLife = restAdapter.create(StudentLife::class.java) @@ -365,31 +382,21 @@ class MainActivity : AppCompatActivity() { fun isOnline(context: Context?): Boolean { val connectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager - if (connectivityManager != null) { - val capabilities = - if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) - } else { - return true - } - } else { - return true - } - if (capabilities != null) { - when { - capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> { - Log.i("Internet", "NetworkCapabilities.TRANSPORT_CELLULAR") - return true - } - capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> { - Log.i("Internet", "NetworkCapabilities.TRANSPORT_WIFI") - return true - } - capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> { - Log.i("Internet", "NetworkCapabilities.TRANSPORT_ETHERNET") - return true - } + val capabilities = + connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) + if (capabilities != null) { + when { + capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> { + Log.i("Internet", "NetworkCapabilities.TRANSPORT_CELLULAR") + return true + } + capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> { + Log.i("Internet", "NetworkCapabilities.TRANSPORT_WIFI") + return true + } + capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> { + Log.i("Internet", "NetworkCapabilities.TRANSPORT_ETHERNET") + return true } } } @@ -397,7 +404,6 @@ fun isOnline(context: Context?): Boolean { } /** Shows an error sneaker given a view group with an optional retry function */ -@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) fun ViewGroup.showSneakerToast(message: String, doOnRetry: (() -> Unit)?, sneakerColor: Int) { val sneaker = Sneaker.with(this) val view = LayoutInflater.from(this.context) diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MenuTab.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MenuTab.kt index ce840a729..b85977681 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MenuTab.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/MenuTab.kt @@ -3,11 +3,9 @@ package com.pennapps.labs.pennmobile import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater -import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.ExpandableListView -import android.widget.LinearLayout import androidx.fragment.app.Fragment import com.pennapps.labs.pennmobile.adapters.MenuAdapter import kotlinx.android.synthetic.main.fragment_menu_tab.view.* diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/NewsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/NewsFragment.kt index ed2c77b76..a97e3fa9e 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/NewsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/NewsFragment.kt @@ -20,17 +20,8 @@ import android.widget.ArrayAdapter import android.widget.ImageView import android.widget.ListView import android.widget.TextView -import androidx.annotation.RequiresApi -import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.preference.PreferenceManager import com.google.firebase.analytics.FirebaseAnalytics -import com.pennapps.labs.pennmobile.components.collapsingtoolbar.ToolbarBehavior -import com.pennapps.labs.pennmobile.utils.Utils -import kotlinx.android.synthetic.main.fragment_about.view.* -import kotlinx.android.synthetic.main.fragment_fitness.* -import kotlinx.android.synthetic.main.fragment_fitness.internetConnectionFitness -import kotlinx.android.synthetic.main.fragment_fitness.internetConnection_message_fitness -import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_news.* import kotlinx.android.synthetic.main.fragment_news.initials import kotlinx.android.synthetic.main.fragment_news.profile_background @@ -115,11 +106,7 @@ class NewsFragment : ListFragment() { val serviceIntent = Intent(SERVICE_ACTION) serviceIntent.setPackage("com.android.chrome") val resolveInfos = context.packageManager.queryIntentServices(serviceIntent, 0) - if (resolveInfos != null ) { - return resolveInfos.isNotEmpty() - } else { - return false - } + return resolveInfos.isNotEmpty() } override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -234,20 +221,11 @@ class NewsFragment : ListFragment() { if (initials != null && initials.isNotEmpty()) { this.initials.text = initials } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - this.profile_background.setImageDrawable( - resources.getDrawable - (R.drawable.ic_guest_avatar, context?.theme)) - } else { - @Suppress("DEPRECATION") - this.profile_background.setImageDrawable( - resources.getDrawable - (R.drawable.ic_guest_avatar)) - } - } - if (Build.VERSION.SDK_INT > 17){ - mActivity?.setSelectedTab(MainActivity.MORE) + this.profile_background.setImageDrawable( + resources.getDrawable + (R.drawable.ic_guest_avatar, context?.theme)) } + mActivity?.setSelectedTab(MainActivity.MORE) } override fun onDestroyView() { diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/PennCourseAlertCreateAlertFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/PennCourseAlertCreateAlertFragment.kt new file mode 100644 index 000000000..0faa0462e --- /dev/null +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/PennCourseAlertCreateAlertFragment.kt @@ -0,0 +1,334 @@ +package com.pennapps.labs.pennmobile + +import android.app.Dialog +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.* +import android.widget.AdapterView.OnItemClickListener +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer +import androidx.preference.PreferenceManager +import com.pennapps.labs.pennmobile.classes.Course +import com.pennapps.labs.pennmobile.classes.Section +import com.pennapps.labs.pennmobile.viewmodels.PennCourseAlertViewModel +import kotlinx.android.synthetic.main.fragment_penn_course_alert_create_alert.view.* +import java.util.regex.Pattern +import androidx.appcompat.widget.Toolbar + +class PennCourseAlertCreateAlertFragment : Fragment() { + private val viewModel: PennCourseAlertViewModel by activityViewModels() + private lateinit var courseSpinner: TextView + private lateinit var sectionSpinner: TextView + private lateinit var dialog: Dialog + private lateinit var mActivity: MainActivity + + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_penn_course_alert_create_alert, container, + false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mActivity = activity as MainActivity + + if (!isOnline(context)) { + showInternetErrorBar(view) + } else { +// hideInternetErrorBar(view) + } + + val sp = PreferenceManager.getDefaultSharedPreferences(activity) + val pennKey = sp.getString(getString(R.string.pennkey), null) + val bearerToken = "Bearer " + sp.getString(getString(R.string.access_token), "").toString() + viewModel.setBearerTokenValue(bearerToken) + + //if guest login + if (pennKey == null) { + handleGuestLogin(view) + } else { + hideGuestErrorMessage(view) + viewModel.getUserInfo() + + + val emailEditText = view.findViewById(R.id.pca_email_edit_text) + + val phoneNumberEditText = view.findViewById(R.id.pca_phone_edit_text) + + viewModel.userInfo.observe(viewLifecycleOwner, Observer { + val formattedPhoneNumber = viewModel.userInfo.value?.profile?.phone?.drop(2) + val email = viewModel.userInfo.value?.profile?.email + + phoneNumberEditText.text = + Editable.Factory.getInstance().newEditable(formattedPhoneNumber?: "") + emailEditText.text = Editable.Factory.getInstance().newEditable(email?: "") + }) + + val alertButton = view.findViewById