diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..49627cc
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,8 @@
+# Windows batch scripts break if checked out with LF endings.
+# This overrides core.autocrlf=input, which would otherwise strip the CRLFs.
+*.bat text eol=crlf
+
+# Unix shell scripts must stay LF, even for contributors on Windows
+# with core.autocrlf=true. CRLF here breaks the shebang under sh/CI/Docker.
+gradlew text eol=lf
+*.sh text eol=lf
diff --git a/.gitignore b/.gitignore
index 37ed22e..1d91a10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,7 +70,7 @@ captures/
.cxx/
# Google Services (e.g. APIs or Firebase)
-# google-services.json
+app/google-services.json
# Freeline
freeline.py
diff --git a/.idea/misc.xml b/.idea/misc.xml
index d302854..8614329 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -36,7 +36,7 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 1b50f37..cb6e54b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,14 +1,14 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.google.gms.google-services'
android {
- compileSdk 34
+ compileSdk 37
defaultConfig {
applicationId "com.cornellappdev.coursegrab"
- minSdkVersion 23
+ minSdkVersion 24
targetSdkVersion 34
versionCode 10
versionName "1.2.0"
@@ -28,39 +28,43 @@ android {
}
}
compileOptions {
- sourceCompatibility = "1.8"
- targetCompatibility = "1.8"
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
- jvmTarget = '1.8'
+ jvmTarget = '11'
}
buildFeatures {
viewBinding true
+ buildConfig true
}
+ namespace 'com.cornellappdev.coursegrab'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation platform('com.google.firebase:firebase-bom:26.0.0')
- implementation 'com.google.firebase:firebase-crashlytics-ktx'
- implementation 'com.google.firebase:firebase-analytics-ktx'
- implementation 'com.google.firebase:firebase-messaging-ktx'
- implementation 'com.google.firebase:firebase-auth-ktx'
+ implementation platform('com.google.firebase:firebase-bom:34.18.0')
+ implementation 'com.google.firebase:firebase-crashlytics'
+ implementation 'com.google.firebase:firebase-analytics'
+ implementation 'com.google.firebase:firebase-messaging'
+ implementation 'com.google.firebase:firebase-auth'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'com.firebaseui:firebase-ui-auth:8.0.0'
- implementation 'com.google.android.gms:play-services-auth:20.0.1'
- implementation 'com.squareup.okhttp3:okhttp:4.9.0'
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0'
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
- implementation 'com.google.code.gson:gson:2.8.6'
- implementation 'androidx.appcompat:appcompat:1.4.1'
- implementation 'androidx.core:core-ktx:1.7.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
- implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
+ implementation 'com.firebaseui:firebase-ui-auth:9.1.1'
+ // Pinned: play-services-auth 22.0.0 removed GoogleSignIn/GoogleSignInClient.
+ // Unpin once LoginActivity/SettingsActivity move to Credential Manager.
+ implementation 'com.google.android.gms:play-services-auth:21.3.0'
+ implementation 'com.squareup.okhttp3:okhttp:5.5.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0'
+ implementation 'com.google.code.gson:gson:2.14.0'
+ implementation 'androidx.appcompat:appcompat:1.8.0'
+ implementation 'androidx.core:core-ktx:1.19.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.2.2'
+ implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0'
testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
- implementation 'androidx.recyclerview:recyclerview:1.2.1'
+ androidTestImplementation 'androidx.test.ext:junit:1.3.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
+ implementation 'androidx.recyclerview:recyclerview:1.4.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
- implementation 'com.google.android.material:material:1.5.0'
+ implementation 'com.google.android.material:material:1.14.0'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0c66b7b..76560ec 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/CourseDetailsActivity.kt b/app/src/main/java/com/cornellappdev/coursegrab/CourseDetailsActivity.kt
index 8f4122e..05a863b 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/CourseDetailsActivity.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/CourseDetailsActivity.kt
@@ -12,6 +12,7 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.cornellappdev.coursegrab.databinding.ActivityCourseDetailsBinding
import com.cornellappdev.coursegrab.models.ApiResponse
import com.cornellappdev.coursegrab.models.Course
import com.cornellappdev.coursegrab.models.SearchResult
@@ -20,14 +21,14 @@ import com.cornellappdev.coursegrab.networking.Request
import com.cornellappdev.coursegrab.networking.addTracking
import com.cornellappdev.coursegrab.networking.removeTracking
import com.google.gson.reflect.TypeToken
-import kotlinx.android.synthetic.main.activity_course_details.*
-import kotlinx.android.synthetic.main.activity_search.back_btn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class CourseDetailsActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityCourseDetailsBinding
+
private lateinit var sectionsRecyclerView: RecyclerView
private lateinit var sectionsViewAdapter: RecyclerView.Adapter<*>
private lateinit var sectionsViewManager: RecyclerView.LayoutManager
@@ -38,26 +39,27 @@ class CourseDetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_course_details)
+ binding = ActivityCourseDetailsBinding.inflate(layoutInflater)
+ setContentView(binding.root)
val courseDetails: SearchResult = intent.getParcelableExtra("courseDetails") as SearchResult
- header_textView.text = "${courseDetails.subject_code} ${courseDetails.course_num}"
+ binding.headerTextView.text = "${courseDetails.subject_code} ${courseDetails.course_num}"
- course_title.text = courseDetails.title
- course_details.text =
+ binding.courseTitle.text = courseDetails.title
+ binding.courseDetails.text =
if (courseDetails.sections.isNotEmpty()) courseDetails.sections.first().instructors.first() else "To Be Assigned"
// Available Courses Adapter
sectionsViewManager = LinearLayoutManager(this@CourseDetailsActivity)
sectionsViewAdapter = SectionAdapter(courseDetails.sections, this@CourseDetailsActivity)
- sectionsRecyclerView = sections_recyclerview.apply {
+ sectionsRecyclerView = binding.sectionsRecyclerview.apply {
layoutManager = sectionsViewManager
adapter = sectionsViewAdapter
}
- back_btn.setOnClickListener { finish() }
+ binding.backBtn.setOnClickListener { finish() }
}
fun addCourse(courseId: Int, context: Context) {
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/LoginActivity.kt b/app/src/main/java/com/cornellappdev/coursegrab/LoginActivity.kt
index 8a4245f..1692912 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/LoginActivity.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/LoginActivity.kt
@@ -4,6 +4,7 @@ import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
+import com.cornellappdev.coursegrab.databinding.ActivityLoginBinding
import com.cornellappdev.coursegrab.models.ApiResponse
import com.cornellappdev.coursegrab.models.Course
import com.cornellappdev.coursegrab.models.UserSession
@@ -20,14 +21,13 @@ import com.google.android.gms.common.api.ApiException
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.reflect.TypeToken
-import kotlinx.android.synthetic.main.activity_login.login_rootView
-import kotlinx.android.synthetic.main.activity_login.sign_in_button
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LoginActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityLoginBinding
private lateinit var googleSignInClient: GoogleSignInClient
private val RC_SIGN_IN = 10032
@@ -37,7 +37,8 @@ class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_login)
+ binding = ActivityLoginBinding.inflate(layoutInflater)
+ setContentView(binding.root)
if (preferencesHelper.expiresAt > System.currentTimeMillis() / 1000L) {
val intent = Intent(this@LoginActivity, MainActivity::class.java)
@@ -72,7 +73,7 @@ class LoginActivity : AppCompatActivity() {
googleSignInClient = GoogleSignIn.getClient(this, gso)
- sign_in_button.setOnClickListener { signIn() }
+ binding.signInButton.setOnClickListener { signIn() }
}
private fun signIn() {
@@ -101,9 +102,9 @@ class LoginActivity : AppCompatActivity() {
}
private fun verifySession(userSession: UserSession) {
- if (userSession.session_expiration.isNullOrEmpty() ||
- userSession.session_token.isNullOrEmpty() ||
- userSession.update_token.isNullOrEmpty()
+ if (userSession.session_expiration.isEmpty() ||
+ userSession.session_token.isEmpty() ||
+ userSession.update_token.isEmpty()
) return
preferencesHelper.sessionToken = userSession.session_token
@@ -128,7 +129,7 @@ class LoginActivity : AppCompatActivity() {
CoroutineScope(Dispatchers.Main).launch {
val typeToken = object : TypeToken>() {}.type
- val response = withContext(Dispatchers.IO) {
+ withContext(Dispatchers.IO) {
Request.makeRequest>(
setNotifs.okHttpRequest(),
typeToken
@@ -166,7 +167,7 @@ class LoginActivity : AppCompatActivity() {
}
} else {
Snackbar.make(
- login_rootView,
+ binding.loginRootView,
"Please use a @cornell.edu account",
Snackbar.LENGTH_LONG
).show()
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/MainActivity.kt b/app/src/main/java/com/cornellappdev/coursegrab/MainActivity.kt
index fc95e2e..bb3cbfb 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/MainActivity.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/MainActivity.kt
@@ -1,11 +1,9 @@
package com.cornellappdev.coursegrab
import android.Manifest
-import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.Editable
@@ -22,8 +20,10 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
+import androidx.core.net.toUri
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.cornellappdev.coursegrab.databinding.ActivityMainBinding
import com.cornellappdev.coursegrab.models.ApiResponse
import com.cornellappdev.coursegrab.models.Course
import com.cornellappdev.coursegrab.models.SearchResult
@@ -35,25 +35,16 @@ import com.cornellappdev.coursegrab.networking.getCourseByID
import com.cornellappdev.coursegrab.networking.getTracking
import com.cornellappdev.coursegrab.networking.removeTracking
import com.google.gson.reflect.TypeToken
-import kotlinx.android.synthetic.main.activity_main.addCourseButton
-import kotlinx.android.synthetic.main.activity_main.addCourseEditText
-import kotlinx.android.synthetic.main.activity_main.available_list
-import kotlinx.android.synthetic.main.activity_main.available_title
-import kotlinx.android.synthetic.main.activity_main.awaiting_list
-import kotlinx.android.synthetic.main.activity_main.awaiting_title
-import kotlinx.android.synthetic.main.activity_main.layout_available
-import kotlinx.android.synthetic.main.activity_main.layout_awaiting
-import kotlinx.android.synthetic.main.activity_main.no_courses_view
-import kotlinx.android.synthetic.main.activity_main.refresh_courses_layout
-import kotlinx.android.synthetic.main.activity_main.search_btn
-import kotlinx.android.synthetic.main.activity_main.settings_btn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import java.util.Locale.getDefault
class MainActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityMainBinding
+
private lateinit var availableRecyclerView: RecyclerView
private lateinit var availableViewAdapter: RecyclerView.Adapter<*>
private lateinit var availableViewManager: RecyclerView.LayoutManager
@@ -68,48 +59,49 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
refreshAwaiting()
- refresh_courses_layout.setOnRefreshListener {
+ binding.refreshCoursesLayout.setOnRefreshListener {
refreshAwaiting()
}
- settings_btn.setOnClickListener {
+ binding.settingsBtn.setOnClickListener {
val intent = Intent(this@MainActivity, SettingsActivity::class.java)
startActivity(intent)
}
- search_btn.setOnClickListener {
+ binding.searchBtn.setOnClickListener {
val intent = Intent(this@MainActivity, SearchActivity::class.java)
startActivity(intent)
}
- addCourseButton.setOnClickListener {
- addCourse(addCourseEditText.text.toString().toInt(), this)
- addCourseEditText.clearFocus()
- addCourseEditText.text.clear()
+ binding.addCourseButton.setOnClickListener {
+ addCourse(binding.addCourseEditText.text.toString().toInt(), this)
+ binding.addCourseEditText.clearFocus()
+ binding.addCourseEditText.text.clear()
val inputMethodManager =
- getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
+ getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0)
}
- addCourseEditText.addTextChangedListener(object : TextWatcher {
+ binding.addCourseEditText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
- addCourseButton.isEnabled = (s!!.length > 3)
+ binding.addCourseButton.isEnabled = (s!!.length > 3)
}
})
- addCourseEditText.setOnKeyListener(View.OnKeyListener { v, keyCode, event ->
+ binding.addCourseEditText.setOnKeyListener(View.OnKeyListener { v, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
- addCourse(addCourseEditText.text.toString().toInt(), this)
- addCourseEditText.clearFocus()
- addCourseEditText.text.clear()
+ addCourse(binding.addCourseEditText.text.toString().toInt(), this)
+ binding.addCourseEditText.clearFocus()
+ binding.addCourseEditText.text.clear()
val inputMethodManager =
- getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
+ getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(v.windowToken, 0)
return@OnKeyListener true
}
@@ -152,7 +144,10 @@ class MainActivity : AppCompatActivity() {
refreshAwaiting()
}
- override fun onBackPressed() {}
+ @Deprecated("Deprecated in Java")
+ override fun onBackPressed() {
+ super.onBackPressed()
+ }
private fun refreshAwaiting() {
val listOpen = mutableListOf()
@@ -167,7 +162,7 @@ class MainActivity : AppCompatActivity() {
getTracking.okHttpRequest(),
typeToken
)
- }!!.data.sections ?: listOf()
+ }!!.data.sections
for (course in courseList) {
if (course.status == "OPEN")
@@ -180,29 +175,31 @@ class MainActivity : AppCompatActivity() {
availableViewManager = LinearLayoutManager(this@MainActivity)
availableViewAdapter = AvailableAdapter(listOpen, this@MainActivity)
- availableRecyclerView = available_list.apply {
+ availableRecyclerView = binding.availableList.apply {
layoutManager = availableViewManager
adapter = availableViewAdapter
}
- available_title.text = "${available_list.adapter?.itemCount} Available"
+ binding.availableTitle.text = "${binding.availableList.adapter?.itemCount} Available"
// Awaiting Courses Adapter
awaitingViewManager = LinearLayoutManager(this@MainActivity)
awaitingViewAdapter = AwaitingAdapter(listAwaiting, this@MainActivity)
- awaitingRecyclerView = awaiting_list.apply {
+ awaitingRecyclerView = binding.awaitingList.apply {
layoutManager = awaitingViewManager
adapter = awaitingViewAdapter
}
- awaiting_title.text = "${awaiting_list.adapter?.itemCount} Awaiting"
+ binding.awaitingTitle.text = "${binding.awaitingList.adapter?.itemCount} Awaiting"
- layout_available.visibility = if (listOpen.isNotEmpty()) View.VISIBLE else View.GONE
- layout_awaiting.visibility = if (listAwaiting.isNotEmpty()) View.VISIBLE else View.GONE
+ binding.layoutAvailable.visibility =
+ if (listOpen.isNotEmpty()) View.VISIBLE else View.GONE
+ binding.layoutAwaiting.visibility =
+ if (listAwaiting.isNotEmpty()) View.VISIBLE else View.GONE
- no_courses_view.visibility =
+ binding.noCoursesView.visibility =
if (listOpen.isEmpty() && listAwaiting.isEmpty()) View.VISIBLE else View.GONE
- refresh_courses_layout.isRefreshing = false
+ binding.refreshCoursesLayout.isRefreshing = false
}
}
@@ -278,9 +275,9 @@ class MainActivity : AppCompatActivity() {
}
}
- private fun enrollCourse(courseId: Int, context: Context) {
+ private fun enrollCourse() {
val browserIntent =
- Intent(Intent.ACTION_VIEW, Uri.parse("http://studentcenter.cornell.edu"))
+ Intent(Intent.ACTION_VIEW, "http://studentcenter.cornell.edu".toUri())
startActivity(browserIntent)
}
@@ -312,7 +309,7 @@ class MainActivity : AppCompatActivity() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.courseTitle.text =
"${availableCourses[position].subject_code} ${availableCourses[position].course_num}: ${availableCourses[position].title}"
- holder.courseTime.text = availableCourses[position].section.toUpperCase()
+ holder.courseTime.text = availableCourses[position].section.uppercase(getDefault())
holder.coursePin.text = availableCourses[position].catalog_num.toString()
holder.courseStatus.setImageResource(if (availableCourses[position].status == "OPEN") R.drawable.ic_status_open else R.drawable.ic_status_closed)
@@ -324,7 +321,6 @@ class MainActivity : AppCompatActivity() {
holder.enrollButton.setOnClickListener {
(context as MainActivity).enrollCourse(
- availableCourses[position].catalog_num, context
)
}
@@ -364,7 +360,7 @@ class MainActivity : AppCompatActivity() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.courseTitle.text =
"${awaitingCourses[position].subject_code} ${awaitingCourses[position].course_num}: ${awaitingCourses[position].title}"
- holder.courseTime.text = awaitingCourses[position].section.toUpperCase()
+ holder.courseTime.text = awaitingCourses[position].section.uppercase(getDefault())
holder.coursePin.text = awaitingCourses[position].catalog_num.toString()
holder.courseStatus.setImageResource(if (awaitingCourses[position].status == "OPEN") R.drawable.ic_status_open else R.drawable.ic_status_closed)
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/NotificationModal.kt b/app/src/main/java/com/cornellappdev/coursegrab/NotificationModal.kt
index 90af256..2ccbe57 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/NotificationModal.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/NotificationModal.kt
@@ -4,30 +4,34 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
+import com.cornellappdev.coursegrab.databinding.ActivityNotificationModalBinding
import com.cornellappdev.coursegrab.models.Course
import com.cornellappdev.coursegrab.models.CourseNotification
-import kotlinx.android.synthetic.main.activity_notification_modal.*
class NotificationModal : AppCompatActivity() {
+ private lateinit var binding: ActivityNotificationModalBinding
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_notification_modal)
+
+ binding = ActivityNotificationModalBinding.inflate(layoutInflater)
+ setContentView(binding.root)
val course: Course =
(intent.getParcelableExtra("courseDetails") as CourseNotification).section
- course_title.text = "${course.subject_code} ${course.course_num}: ${course.title}"
- course_section.text = course.section
- course_pin.text = course.catalog_num.toString()
+ binding.courseTitle.text = "${course.subject_code} ${course.course_num}: ${course.title}"
+ binding.courseSection.text = course.section
+ binding.coursePin.text = course.catalog_num.toString()
- button_student_center.setOnClickListener {
+ binding.buttonStudentCenter.setOnClickListener {
val browserIntent =
Intent(Intent.ACTION_VIEW, Uri.parse("http://studentcenter.cornell.edu"))
startActivity(browserIntent)
}
- button_back_home.setOnClickListener {
+ binding.buttonBackHome.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/NotificationService.kt b/app/src/main/java/com/cornellappdev/coursegrab/NotificationService.kt
index abd39f3..57a5a7f 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/NotificationService.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/NotificationService.kt
@@ -3,7 +3,6 @@ package com.cornellappdev.coursegrab
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
-import android.content.Context
import android.content.Intent
import android.media.RingtoneManager
import android.os.Build
@@ -35,7 +34,6 @@ class NotificationService : FirebaseMessagingService() {
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
override fun onMessageReceived(remoteMessage: RemoteMessage) {
-// Log.d("Networking", remoteMessage.data.toString())
// Check if message contains a data payload.
remoteMessage.data.isNotEmpty().let {
val courseInfoRaw = Gson()
@@ -59,6 +57,7 @@ class NotificationService : FirebaseMessagingService() {
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
+ @Deprecated("Deprecated in Java")
override fun onNewToken(token: String) {
sendRegistrationToServer(token)
}
@@ -79,15 +78,12 @@ class NotificationService : FirebaseMessagingService() {
CoroutineScope(Dispatchers.Main).launch {
val typeToken = object : TypeToken>() {}.type
- val response = withContext(Dispatchers.IO) {
+ withContext(Dispatchers.IO) {
Request.makeRequest>(
sendDeviceToken.okHttpRequest(),
typeToken
)
}
-
-// if (response!!.success)
-// Log.d("NotificationService", "sendRegistrationTokenToServer($token)")
}
}
@@ -102,7 +98,7 @@ class NotificationService : FirebaseMessagingService() {
intent.putExtra("courseDetails", course)
val pendingIntent = PendingIntent.getActivity(
this, 10032, intent,
- PendingIntent.FLAG_ONE_SHOT
+ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
val channelId = getString(R.string.default_notification_channel_id)
@@ -119,7 +115,7 @@ class NotificationService : FirebaseMessagingService() {
)
val notificationManager =
- getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ getSystemService(NOTIFICATION_SERVICE) as NotificationManager
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/PreferencesHelper.kt b/app/src/main/java/com/cornellappdev/coursegrab/PreferencesHelper.kt
index 1081453..8849b27 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/PreferencesHelper.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/PreferencesHelper.kt
@@ -2,6 +2,7 @@ package com.cornellappdev.coursegrab
import android.content.Context
import android.preference.PreferenceManager
+import androidx.core.content.edit
class PreferencesHelper(context: Context) {
@@ -9,36 +10,36 @@ class PreferencesHelper(context: Context) {
var sessionToken = preferences.getString(SESSION_TOKEN, "")
set(value) {
- preferences.edit().putString(SESSION_TOKEN, value).apply()
+ preferences.edit { putString(SESSION_TOKEN, value) }
field = preferences.getString(SESSION_TOKEN, "")
}
var updateToken = preferences.getString(UPDATE_TOKEN, "")
set(value) {
- preferences.edit().putString(UPDATE_TOKEN, value).apply()
+ preferences.edit { putString(UPDATE_TOKEN, value) }
field = preferences.getString(UPDATE_TOKEN, "")
}
var expiresAt = preferences.getLong(EXPIRES_AT, 0L)
set(value) {
- preferences.edit().putLong(EXPIRES_AT, value).apply()
+ preferences.edit { putLong(EXPIRES_AT, value) }
field = preferences.getLong(EXPIRES_AT, 0L)
}
var emailAlertSetting = preferences.getBoolean(EMAIL_ALERTS, true)
set(value) {
- preferences.edit().putBoolean(EMAIL_ALERTS, value).apply()
+ preferences.edit { putBoolean(EMAIL_ALERTS, value) }
field = preferences.getBoolean(EMAIL_ALERTS, true)
}
var mobileAlertSetting = preferences.getBoolean(MOBILE_ALERTS, true)
set(value) {
- preferences.edit().putBoolean(MOBILE_ALERTS, value).apply()
+ preferences.edit { putBoolean(MOBILE_ALERTS, value) }
field = preferences.getBoolean(MOBILE_ALERTS, true)
}
fun clearAll() {
- preferences.edit().clear().commit()
+ preferences.edit(commit = true) { clear() }
}
companion object {
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/SearchActivity.kt b/app/src/main/java/com/cornellappdev/coursegrab/SearchActivity.kt
index a9bb47f..3468c2e 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/SearchActivity.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/SearchActivity.kt
@@ -1,6 +1,5 @@
package com.cornellappdev.coursegrab
-import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
@@ -16,6 +15,7 @@ import androidx.core.content.ContextCompat
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.cornellappdev.coursegrab.databinding.ActivitySearchBinding
import com.cornellappdev.coursegrab.models.ApiResponse
import com.cornellappdev.coursegrab.models.SearchContainer
import com.cornellappdev.coursegrab.models.SearchResult
@@ -23,13 +23,14 @@ import com.cornellappdev.coursegrab.networking.Endpoint
import com.cornellappdev.coursegrab.networking.Request
import com.cornellappdev.coursegrab.networking.searchCourses
import com.google.gson.reflect.TypeToken
-import kotlinx.android.synthetic.main.activity_search.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SearchActivity : AppCompatActivity() {
+ private lateinit var binding: ActivitySearchBinding
+
private lateinit var searchRecyclerView: RecyclerView
private lateinit var searchViewAdapter: RecyclerView.Adapter<*>
private lateinit var searchViewManager: RecyclerView.LayoutManager
@@ -40,37 +41,38 @@ class SearchActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_search)
+ binding = ActivitySearchBinding.inflate(layoutInflater)
+ setContentView(binding.root)
- editText_search.setOnKeyListener(View.OnKeyListener { v, keyCode, event ->
+ binding.editTextSearch.setOnKeyListener(View.OnKeyListener { v, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
- searchCourses(editText_search.text.toString())
+ searchCourses(binding.editTextSearch.text.toString())
val inputMethodManager =
- getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
+ getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(v.windowToken, 0)
return@OnKeyListener true
}
false
})
- editText_search.doOnTextChanged { text, _, _, count ->
+ binding.editTextSearch.doOnTextChanged { text, _, _, _ ->
if ((text ?: "").length > 2) {
searchCourses(text.toString())
} else {
- layout_results.visibility = View.GONE
- no_results_view.visibility = View.VISIBLE
- no_results_icon.setImageDrawable(
+ binding.layoutResults.visibility = View.GONE
+ binding.noResultsView.visibility = View.VISIBLE
+ binding.noResultsIcon.setImageDrawable(
ContextCompat.getDrawable(
this,
R.drawable.ic_status_warning
)
);
- no_results_title.text = getString(R.string.requires_longer_search)
- no_results_subtitle.text = getString(R.string.requires_longer_search_subtext)
+ binding.noResultsTitle.text = getString(R.string.requires_longer_search)
+ binding.noResultsSubtitle.text = getString(R.string.requires_longer_search_subtext)
}
}
- back_btn.setOnClickListener { finish() }
+ binding.backBtn.setOnClickListener { finish() }
}
private fun searchCourses(query: String) {
@@ -85,29 +87,31 @@ class SearchActivity : AppCompatActivity() {
)
}!!.data.courses
- if (editText_search.text.toString() != query)
+ if (binding.editTextSearch.text.toString() != query)
return@launch;
// Results Courses Adapter
searchViewManager = LinearLayoutManager(this@SearchActivity)
searchViewAdapter = ResultsAdapter(courseList, this@SearchActivity)
- searchRecyclerView = results_list.apply {
+ searchRecyclerView = binding.resultsList.apply {
layoutManager = searchViewManager
adapter = searchViewAdapter
}
- result_title.text = "${results_list.adapter?.itemCount} Results"
+ binding.resultTitle.text = "${binding.resultsList.adapter?.itemCount} Results"
- layout_results.visibility = if (courseList.isNotEmpty()) View.VISIBLE else View.GONE
- no_results_view.visibility = if (courseList.isEmpty()) View.VISIBLE else View.GONE
- no_results_icon.setImageDrawable(
+ binding.layoutResults.visibility =
+ if (courseList.isNotEmpty()) View.VISIBLE else View.GONE
+ binding.noResultsView.visibility = if (courseList.isEmpty()) View.VISIBLE else View.GONE
+ binding.noResultsIcon.setImageDrawable(
ContextCompat.getDrawable(
this@SearchActivity,
R.drawable.ic_status_closed
)
);
- no_results_title.text = getString(R.string.no_courses_alert)
- no_results_subtitle.text = getString(R.string.no_results_alert_subtext_try_another)
+ binding.noResultsTitle.text = getString(R.string.no_courses_alert)
+ binding.noResultsSubtitle.text =
+ getString(R.string.no_results_alert_subtext_try_another)
}
}
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/SettingsActivity.kt b/app/src/main/java/com/cornellappdev/coursegrab/SettingsActivity.kt
index f614c55..10355dc 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/SettingsActivity.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/SettingsActivity.kt
@@ -3,12 +3,13 @@ package com.cornellappdev.coursegrab
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
-import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
+import androidx.core.net.toUri
+import com.cornellappdev.coursegrab.databinding.ActivitySettingsBinding
import com.cornellappdev.coursegrab.models.ApiResponse
import com.cornellappdev.coursegrab.models.Course
import com.cornellappdev.coursegrab.networking.Endpoint
@@ -19,12 +20,6 @@ import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.reflect.TypeToken
-import kotlinx.android.synthetic.main.activity_settings.back_btn
-import kotlinx.android.synthetic.main.activity_settings.class_roster
-import kotlinx.android.synthetic.main.activity_settings.cornell_academic_calendar
-import kotlinx.android.synthetic.main.activity_settings.email_alerts_switch
-import kotlinx.android.synthetic.main.activity_settings.mobile_alerts_switch
-import kotlinx.android.synthetic.main.activity_settings.sign_out
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -32,6 +27,7 @@ import kotlinx.coroutines.withContext
class SettingsActivity : AppCompatActivity() {
+ private lateinit var binding: ActivitySettingsBinding
private lateinit var googleSignInClient: GoogleSignInClient
private val preferencesHelper: PreferencesHelper by lazy {
@@ -40,16 +36,17 @@ class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_settings)
+ binding = ActivitySettingsBinding.inflate(layoutInflater)
+ setContentView(binding.root)
- email_alerts_switch.isChecked = preferencesHelper.emailAlertSetting
- mobile_alerts_switch.isChecked = preferencesHelper.mobileAlertSetting
+ binding.emailAlertsSwitch.isChecked = preferencesHelper.emailAlertSetting
+ binding.mobileAlertsSwitch.isChecked = preferencesHelper.mobileAlertSetting
- email_alerts_switch.setOnCheckedChangeListener { _, isChecked ->
+ binding.emailAlertsSwitch.setOnCheckedChangeListener { _, isChecked ->
preferencesHelper.emailAlertSetting = isChecked
}
- mobile_alerts_switch.setOnCheckedChangeListener { _, isChecked ->
+ binding.mobileAlertsSwitch.setOnCheckedChangeListener { _, isChecked ->
if (
Build.VERSION.SDK_INT >= 33 &&
ContextCompat.checkSelfPermission(
@@ -77,27 +74,27 @@ class SettingsActivity : AppCompatActivity() {
googleSignInClient = GoogleSignIn.getClient(this, gso)
- class_roster.setOnClickListener {
+ binding.classRoster.setOnClickListener {
val browserIntent =
- Intent(Intent.ACTION_VIEW, Uri.parse("https://classes.cornell.edu/"))
+ Intent(Intent.ACTION_VIEW, "https://classes.cornell.edu/".toUri())
startActivity(browserIntent)
}
- cornell_academic_calendar.setOnClickListener {
+ binding.cornellAcademicCalendar.setOnClickListener {
val browserIntent =
Intent(
Intent.ACTION_VIEW,
- Uri.parse("https://registrar.cornell.edu/academic-calendar")
+ "https://registrar.cornell.edu/academic-calendar".toUri()
)
startActivity(browserIntent)
}
- sign_out.setOnClickListener {
+ binding.signOut.setOnClickListener {
preferencesHelper.clearAll()
signOut()
}
- back_btn.setOnClickListener { finish() }
+ binding.backBtn.setOnClickListener { finish() }
if (
Build.VERSION.SDK_INT >= 33 &&
@@ -106,8 +103,8 @@ class SettingsActivity : AppCompatActivity() {
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
- mobile_alerts_switch.isChecked = false
- mobile_alerts_switch.isEnabled = false
+ binding.mobileAlertsSwitch.isChecked = false
+ binding.mobileAlertsSwitch.isEnabled = false
}
}
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/models/Course.kt b/app/src/main/java/com/cornellappdev/coursegrab/models/Course.kt
index 31871d9..d2058ed 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/models/Course.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/models/Course.kt
@@ -1,7 +1,7 @@
package com.cornellappdev.coursegrab.models
import android.os.Parcelable
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.Parcelize
@Parcelize
data class Course(
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/models/CourseNotification.kt b/app/src/main/java/com/cornellappdev/coursegrab/models/CourseNotification.kt
index d5c13e4..094b2c9 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/models/CourseNotification.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/models/CourseNotification.kt
@@ -1,7 +1,7 @@
package com.cornellappdev.coursegrab.models
import android.os.Parcelable
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.Parcelize
@Parcelize
data class CourseNotification(
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/models/SearchContainer.kt b/app/src/main/java/com/cornellappdev/coursegrab/models/SearchContainer.kt
index da186aa..0f9ac7c 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/models/SearchContainer.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/models/SearchContainer.kt
@@ -1,7 +1,7 @@
package com.cornellappdev.coursegrab.models
import android.os.Parcelable
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.Parcelize
@Parcelize
data class SearchContainer(
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/models/SearchResult.kt b/app/src/main/java/com/cornellappdev/coursegrab/models/SearchResult.kt
index 1b08d04..0585e2f 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/models/SearchResult.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/models/SearchResult.kt
@@ -1,7 +1,7 @@
package com.cornellappdev.coursegrab.models
import android.os.Parcelable
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.Parcelize
@Parcelize
data class SearchResult(
diff --git a/app/src/main/java/com/cornellappdev/coursegrab/models/TrackingContainer.kt b/app/src/main/java/com/cornellappdev/coursegrab/models/TrackingContainer.kt
index 2fe2237..f7d3d5d 100644
--- a/app/src/main/java/com/cornellappdev/coursegrab/models/TrackingContainer.kt
+++ b/app/src/main/java/com/cornellappdev/coursegrab/models/TrackingContainer.kt
@@ -1,7 +1,7 @@
package com.cornellappdev.coursegrab.models
import android.os.Parcelable
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.Parcelize
@Parcelize
data class TrackingContainer(
diff --git a/build.gradle b/build.gradle
index 9f5cbee..64de89f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,18 +4,13 @@ buildscript {
ext.kotlin_version = '1.4.21'
repositories {
google()
- jcenter()
-
- maven {
- url 'https://maven.fabric.io/public'
- }
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.4.2'
- classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21'
- classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2'
- classpath 'io.fabric.tools:gradle:1.31.2'
+ classpath 'com.android.tools.build:gradle:9.3.2'
+ classpath 'com.google.gms:google-services:4.5.0'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.10'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -24,11 +19,11 @@ buildscript {
allprojects {
repositories {
google()
- jcenter()
+ mavenCentral()
}
}
-task clean(type: Delete) {
+tasks.register('clean', Delete) {
delete rootProject.buildDir
}
diff --git a/gradle.properties b/gradle.properties
index 23339e0..f26acd6 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -19,3 +19,16 @@ android.useAndroidX=true
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
+android.nonTransitiveRClass=false
+android.nonFinalResIds=false
+android.defaults.buildfeatures.resvalues=true
+android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
+android.enableAppCompileTimeRClass=false
+android.usesSdkInManifest.disallowed=false
+android.uniquePackageNames=false
+android.dependency.useConstraints=true
+android.r8.strictFullModeForKeepRules=false
+android.r8.optimizedResourceShrinking=false
+android.builtInKotlin=false
+android.newDsl=false
+android.buildFeatures.buildConfig = true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index f6b961f..eddabd2 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 1630233..4dddcf8 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,10 @@
-#Sat Nov 07 21:59:23 EST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
+distributionSha256Sum=acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a
+networkTimeout=10000
+retries=0
+retryBackOffMs=500
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
diff --git a/gradlew b/gradlew
old mode 100644
new mode 100755
index cccdd3d..249efbb
--- a/gradlew
+++ b/gradlew
@@ -1,78 +1,128 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# gradlew start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh gradlew
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,92 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=$((i+1))
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
fi
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index f955316..a51ec4f 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,84 +1,82 @@
-@if "%DEBUG%" == "" @echo off
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
-@rem Gradle startup script for Windows
+@rem gradlew startup script for Windows
@rem
@rem ##########################################################################
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
-goto fail
+"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
+"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
+@rem Execute gradlew
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-:omega
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%
diff --git a/settings.gradle b/settings.gradle
index 1e81e2c..c300885 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,5 @@
+plugins {
+ id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
+}
include ':app'
rootProject.name='CourseGrab'