Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0bb66d7
Merge pull request #79 from yeSpud/Open-Testing
yeSpud Sep 14, 2021
ef8ffd9
Merge pull request #89 from yeSpud/Open-Testing
yeSpud May 5, 2022
7f11e7c
Merge pull request #91 from yeSpud/Open-Testing
yeSpud May 5, 2022
5d77b10
Merge pull request #94 from yeSpud/Open-Testing
yeSpud Jun 13, 2022
cf45824
Added a privacy policy for data collection
yeSpud Aug 11, 2022
859e1c2
Merge pull request #96 from yeSpud/Open-Testing
yeSpud Oct 11, 2022
51b2e1c
Merge pull request #99 from yeSpud/Open-Testing
yeSpud Jan 12, 2024
3562922
Merge pull request #104 from yeSpud/Open-Testing
yeSpud Oct 23, 2024
440c5d5
Merge pull request #108 from yeSpud/Open-Testing
yeSpud Oct 22, 2025
24bef62
Added floating action buttons to map activity
yeSpud Oct 22, 2025
b941c3b
Merge branch 'Production' into new_menu
yeSpud Oct 22, 2025
84cf406
Added buttons for settings, fares, and future route menu
yeSpud Oct 23, 2025
e4ae767
Added settings icon
yeSpud Oct 23, 2025
afd9c67
Created a custom view for selectable routes in the custom menu
yeSpud Oct 30, 2025
f565475
Added MVP route menu
yeSpud Nov 4, 2025
b3751df
Added close button to menu
yeSpud Nov 6, 2025
b02e7b8
Save favorite routes on close
yeSpud Nov 26, 2025
1b2a1d5
Only redraw routes on close
yeSpud Nov 26, 2025
132fae0
Clicking the route name checks the box
yeSpud Nov 26, 2025
82a0c68
Added icons for broadcasting buses
yeSpud Nov 26, 2025
fc25b42
Added routes and fares icons
yeSpud Nov 26, 2025
83aa1f3
Added content descriptions for FABs
yeSpud Nov 26, 2025
e9b65a1
Updated build information for beta release
yeSpud Nov 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ android {
applicationId "fnsb.macstransit"
minSdk 27
targetSdk 36
versionCode 33
versionName 'Release 1.4.2'
versionCode 34
versionName 'Release 1.5'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
Expand Down Expand Up @@ -62,13 +62,14 @@ dependencies {
implementation 'com.android.volley:volley:1.2.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.10.0'
implementation 'com.google.maps.android:maps-ktx:5.2.1'
implementation 'com.google.maps.android:maps-utils-ktx:5.2.1'
implementation 'com.google.maps.android:android-maps-utils:3.19.0'
implementation 'com.google.maps.android:android-maps-utils:3.19.1'
implementation 'androidx.annotation:annotation-jvm:1.9.1'
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
implementation 'com.orhanobut:dialogplus:1.11@aar'
implementation 'com.google.android.material:material:1.13.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.json:json:20250517'
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import fnsb.macstransit.routematch.Route
import fnsb.macstransit.settings.V2
import fnsb.macstransit.R
import android.util.Log
import android.view.Gravity
import android.view.Menu
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
Expand All @@ -15,9 +17,11 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.gms.maps.SupportMapFragment
import com.orhanobut.dialogplus.DialogPlus
import fnsb.macstransit.activities.LoadedRoutes
import fnsb.macstransit.activities.SettingsActivity
import fnsb.macstransit.activities.mapsactivity.mappopups.FarePopupWindow
import fnsb.macstransit.activities.mapsactivity.mappopups.RouteMenu
import fnsb.macstransit.databinding.ActivityMapsBinding
import fnsb.macstransit.routematch.Bus
import fnsb.macstransit.routematch.SharedStop
Expand All @@ -34,12 +38,14 @@ class MapsActivity: FragmentActivity() {
* The view model for the maps activity.
* This is usually where all the large functions and additional properties are.
*/
private lateinit var viewModel: MapsViewModel
lateinit var viewModel: MapsViewModel

/**
* Create a variable to store our fare popup window instance.
*/
private lateinit var farePopupWindow: FarePopupWindow
lateinit var farePopupWindow: FarePopupWindow

lateinit var routeMenu: DialogPlus

override fun onCreate(savedInstanceState: Bundle?) {
Log.v("onCreate", "onCreate has been called!")
Expand All @@ -52,6 +58,7 @@ class MapsActivity: FragmentActivity() {
val binding: ActivityMapsBinding = ActivityMapsBinding.inflate(layoutInflater)
binding.viewmodel = viewModel
binding.lifecycleOwner = this
binding.activity = this

// Set the activity view to the map activity layout.
setContentView(binding.root)
Expand Down Expand Up @@ -149,139 +156,6 @@ class MapsActivity: FragmentActivity() {
Log.v("onDestroy", "Finished onDestroy")
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
Log.v("onCreateOptionsMenu", "onCreateOptionsMenu has been called!")

// Setup the inflater.
menuInflater.inflate(R.menu.menu, menu)

// Create the menu item that corresponds to the route object.
for (name in LoadedRoutes.routes.keys) {

// Make sure the item is checkable.
menu.add(R.id.routes, name.hashCode(), Menu.NONE, name).isCheckable = true
}

// Return what ever the default behaviour would be when calling this method if it were not overridden.
return super.onCreateOptionsMenu(menu)
}

override fun onPrepareOptionsMenu(menu: Menu): Boolean {
Log.v("onPrepareOptionsMenu", "onPrepareOptionsMenu has been called!")

// Iterate through all the routes that can be tracked (if allRoutes isn't null).
for ((name, route) in LoadedRoutes.routes) {

// Determine whether or not the menu item should be checked before hand.
val checked: Boolean = route.enabled

// Set the menu item to be checked if the route it corresponds to is enabled.
Log.d("onPrepareOptionsMenu", "Setting $name to be enabled: $checked")
menu.findItem(name.hashCode()).isChecked = checked
}

// Check if night mode should be enabled by default, and set the checkbox to that value.
menu.findItem(R.id.night_mode).isChecked = (CurrentSettings.settingsImplementation as V2).darktheme

// Return what ever the default behaviour would be when calling this method if it were not overridden.
return super.onPrepareOptionsMenu(menu)
}

override fun onOptionsItemSelected(item: android.view.MenuItem): Boolean {
Log.v("onOptionsItemSelected", "onOptionsItemSelected has been called!")

// Identify which method to call based on the item ID.
// Check if the item that was selected belongs to the other group
when (item.groupId) {
R.id.other -> {

// Identify what action to execute based on the item ID.
when (item.itemId) {

// Check if the item that was selected was the night mode toggle.
R.id.night_mode -> {
if (viewModel.map == null) {
return false
}

Log.d("onOptionsItemSelected", "Toggling night mode...")

// Create a boolean to store the resulting value of the menu item.
val enabled = !item.isChecked

// Toggle night mode
MapsViewModel.toggleNightMode(viewModel.map!!, this, enabled)

// Set the menu item's checked value to that of the enabled value.
item.isChecked = enabled
}

// Check if the item that was selected was the settings button.
R.id.settings -> {

// Create the intent to launch the settings activity.
val settingsIntent = android.content.Intent(this, SettingsActivity::class.java)

// Start the settings activity.
startActivity(settingsIntent)
}

// Check if the item that was selected was the fares button.
R.id.fares -> farePopupWindow.showFarePopupWindow()

// Since the item's ID was not part of anything accounted for (uh oh), log it as a warning!
else -> Log.w("onOptionsItemSelected", "Unaccounted menu item in the other group was checked!")
}
}

// Check if the item that was selected belongs to the routes group.
R.id.routes -> {

// Create a boolean to store the resulting value of the menu item.
val enabled = !item.isChecked

// Get the route that was selected.
val route: Route = LoadedRoutes.routes[item.title] ?: return super.onOptionsItemSelected(item)

// Set the route to enabled.
route.enabled = enabled
Log.d("onOptionsItemSelected", "Selected route ${route.name}")

// If the map is null at this point just return early (skip redrawing).
if (viewModel.map == null) {
return super.onOptionsItemSelected(item)
}

// Try to (re)draw the buses onto the map.
// Because we are iterating a static variable that is modified on a different thread
// there is a possibility of a concurrent modification.
try {
viewModel.drawBuses()
} catch (e: ConcurrentModificationException) {
Log.e("onOptionsItemSelected",
"Unable to redraw all buses due to concurrent modification", e)
}

// (Re) draw the stops onto the map.
viewModel.drawStops()

// (Re) draw the routes onto the map (if enabled).
if ((CurrentSettings.settingsImplementation as V2).polylines) {
viewModel.drawRoutes()
}

// Set the menu item's checked value to that of the enabled value
item.isChecked = enabled
}

// Since the item's ID and group was not part of anything accounted for (uh oh), log it as a warning!
else -> Log.w("onOptionsItemSelected", "Unaccounted menu item was checked!")
}

// Return what ever the default behaviour would be when calling this method if it were not overridden.
return super.onOptionsItemSelected(item)
}

override fun onResume() {
Log.v("onResume", "onResume has been called!")
super.onResume()
Expand All @@ -305,6 +179,32 @@ class MapsActivity: FragmentActivity() {
}
}

fun showRoutesMenu() {

// Constantly recreating the dialog window is wasteful,
// but it fixes a bug where after the menu was dismissed its height would be crushed back down to minimums
routeMenu = DialogPlus.newDialog(this)
.setAdapter(RouteMenu(this))
.setContentBackgroundResource(R.color.colorPrimaryDark)
.setExpanded(false)
.setGravity(Gravity.CENTER)
.setContentWidth(ViewGroup.LayoutParams.MATCH_PARENT)
.setContentHeight(ViewGroup.LayoutParams.WRAP_CONTENT)
.setOnDismissListener { dialog -> RouteMenu.onDismissListener(this, dialog) }
.create()

routeMenu.show()
}

fun launchSettingsActivity() {

// Create the intent to launch the settings activity.
val settingsIntent = android.content.Intent(this, SettingsActivity::class.java)

// Start the settings activity.
startActivity(settingsIntent)
}

companion object {

/**
Expand Down
Loading