Author: Adam <git@apiote.xyz>
show results
%!v(PANIC=String method: strings: negative Repeat count)
diff --git a/app/build.gradle b/app/build.gradle index 531c315cc944a899545d8da178ed65f28e05ef7d..3d4a926b038c33d79e7f9a00f2117c12261ca0c8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,7 +36,7 @@ } dependencies { implementation 'androidx.core:core-ktx:1.8.0' - implementation 'androidx.appcompat:appcompat:1.4.2' + implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'com.google.android.material:material:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1' @@ -44,6 +44,8 @@ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' implementation 'androidx.navigation:navigation-fragment-ktx:2.5.1' implementation 'androidx.navigation:navigation-ui-ktx:2.5.1' implementation 'com.github.mancj:MaterialSearchBar:0.8.5' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'com.google.openlocationcode:openlocationcode:1.0.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9c503d0a03800560f34ad69ca50f72d79c28c148..88fa50c2e6286f4d53688dce0b3860a058798f69 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,29 +1,37 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="ml.adamsprogs.bimba"> + xmlns:tools="http://schemas.android.com/tools" + package="ml.adamsprogs.bimba"> - <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> - <application - android:allowBackup="true" - android:dataExtractionRules="@xml/data_extraction_rules" - android:fullBackupContent="@xml/backup_rules" - android:icon="@mipmap/ic_launcher" - android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" - android:supportsRtl="true" - android:theme="@style/Theme.Bimba.Style" - tools:targetApi="31"> - <activity - android:windowSoftInputMode="adjustPan" - android:name=".MainActivity" - android:exported="true"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> + <application + android:allowBackup="true" + android:dataExtractionRules="@xml/data_extraction_rules" + android:fullBackupContent="@xml/backup_rules" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@style/Theme.Bimba.Style" + tools:targetApi="31"> + <activity + android:name=".search.ResultsActivity" + android:exported="false" + android:label="@string/title_activity_results" + android:theme="@style/Theme.Bimba.Style" /> + <activity + android:name=".dashboard.MainActivity" + android:exported="true" + android:windowSoftInputMode="adjustPan"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt deleted file mode 100644 index 8d14f2452cbe85342ece2b487ee42417fe7cd3c3..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt +++ /dev/null @@ -1,82 +0,0 @@ -package ml.adamsprogs.bimba - -import android.os.Bundle -import android.view.View -import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.get -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks -import androidx.navigation.fragment.NavHostFragment -import androidx.navigation.ui.setupWithNavController -import com.google.android.material.bottomnavigation.BottomNavigationView -import ml.adamsprogs.bimba.databinding.ActivityMainBinding -import ml.adamsprogs.bimba.ui.home.HomeFragment -import ml.adamsprogs.bimba.ui.map.MapFragment -import ml.adamsprogs.bimba.ui.voyage.VoyageFragment - - -class MainActivity : AppCompatActivity() { - - private lateinit var binding: ActivityMainBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) - - supportFragmentManager.registerFragmentLifecycleCallbacks( - object : FragmentLifecycleCallbacks() { - override fun onFragmentViewCreated( - fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle? - ) { - setNavbarIcons(f) - super.onFragmentViewCreated(fm, f, v, savedInstanceState) - } - }, true - ) - - val navView: BottomNavigationView = binding.bottomNavigation - val navHostFragment = - supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment - val navController = navHostFragment.navController - navView.setupWithNavController(navController) - } - - override fun onBackPressed() { - if (binding.container.isDrawerOpen(binding.navigationDrawer)) { - binding.container.closeDrawer(binding.navigationDrawer) - }else { - super.onBackPressed() - } - } - - fun onNavigationClicked() { - if (binding.container.isDrawerOpen(binding.navigationDrawer)) { - binding.container.closeDrawer(binding.navigationDrawer) - } else { - binding.container.openDrawer(binding.navigationDrawer) - } - } - - private fun setNavbarIcons(f: Fragment) { - binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_outline_24dp) - binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_outline_24dp) - binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_outline_24dp) - when (f) { - is HomeFragment -> { - binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp) - } - is VoyageFragment -> { - binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_black_24dp) - } - is MapFragment -> { - binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_black_24dp) - } - else -> { - binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt b/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt deleted file mode 100644 index e15982f0f24088c350a771969939eb12bb11fb86..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt +++ /dev/null @@ -1,161 +0,0 @@ -package ml.adamsprogs.bimba.api - -import android.util.Log -import xyz.apiote.fruchtfleisch.Reader -import java.io.InputStream - -data class Stop( - val name: String, - val code: String, - val zone: String, - val position: String, - val changeOptions: List<ChangeOption> -) { - override fun toString(): String { - var result = "$name ($code) [$zone] $position\n" - for (chOpt in changeOptions) - result += "${chOpt.line} → ${chOpt.headsign}\n" - return result - } - - companion object { - fun unmarshall(stream: InputStream): Stop { - val reader = Reader(stream) - val code = reader.readString() - val zone = reader.readString() - val position = reader.readString() - val chOptionsNum = reader.readUInt() - val changeOptions = mutableListOf<ChangeOption>() - for (i in 0UL until chOptionsNum) { - changeOptions.add(ChangeOption.unmarshall(stream)) - } - val name = reader.readString() - return Stop( - name = name, - code = code, - zone = zone, - position = position, - changeOptions = changeOptions - ) - } - } -} - -data class Line( - val name: String, - val textColour: UInt, - val colour: UInt, - val type: LineType, - val headsignsThere: List<String>, - val headsignsBack: List<String>, - val graphThere: LineGraph, - val graphBack: LineGraph -) { - override fun toString(): String { - return "$name ($type) [$textColour/$colour]\n→ [${headsignsThere.joinToString()}]\n→ [${headsignsBack.joinToString()}]\n" - } - - companion object { - fun unmarshall(stream: InputStream): Line { - val reader = Reader(stream) - val textColour = reader.readUInt().toUInt() - val colour = reader.readUInt().toUInt() - val type = reader.readUInt() - val headsignsThereNum = reader.readUInt() - val headsignsThere = mutableListOf<String>() - for (i in 0UL until headsignsThereNum) { - headsignsThere.add(reader.readString()) - } - val headsignsBackNum = reader.readUInt() - val headsignsBack = mutableListOf<String>() - for (i in 0UL until headsignsBackNum) { - headsignsBack.add(reader.readString()) - } - val graphThere = LineGraph.unmarshall(stream) - val graphBack = LineGraph.unmarshall(stream) - val name = reader.readString() - return Line( - name = name, textColour = textColour, - colour = colour, type = LineType(type.toUInt()), headsignsThere = headsignsThere, - headsignsBack = headsignsBack, graphThere = graphThere, graphBack = graphBack - ) - } - } -} - -enum class LineType { - TRAM, BUS, UNKNOWN -} - -fun LineType(type: UInt): LineType { - Log.d("LineType", "$type") - return when (type) { - 0U -> LineType.valueOf("TRAM") - 3U -> LineType.valueOf("BUS") - else -> LineType.valueOf("UNKNOWN") - } -} - -data class ChangeOption(val line: String, val headsign: String) { - companion object { - fun unmarshall(stream: InputStream): ChangeOption { - val reader = Reader(stream) - return ChangeOption(line = reader.readString(), headsign = reader.readString()) - } - } -} - -data class LineGraph( - val stops: List<StopStub>, - val nextNodes: Map<Long, List<Long>>, - val prevNodes: Map<Long, List<Long>> -) { - companion object { - fun unmarshall(stream: InputStream): LineGraph { - val reader = Reader(stream) - val stopsNum = reader.readUInt() - val stops = mutableListOf<StopStub>() - for (i in 0UL until stopsNum) { - stops.add(StopStub.unmarshall(stream)) - } - val nextNodesNum = reader.readUInt() - val nextNodes = mutableMapOf<Long, List<Long>>() - for (i in 0UL until nextNodesNum) { - val from = reader.readInt() - val toNum = reader.readUInt() - val to = mutableListOf<Long>() - for (j in 0UL until toNum) { - to.add(reader.readInt()) - } - nextNodes[from] = to - } - val prevNodesNum = reader.readUInt() - val prevNodes = mutableMapOf<Long, List<Long>>() - for (i in 0UL until prevNodesNum) { - val from = reader.readInt() - val toNum = reader.readUInt() - val to = mutableListOf<Long>() - for (j in 0UL until toNum) { - to.add(reader.readInt()) - } - prevNodes[from] = to - } - - return LineGraph(stops = stops, nextNodes = nextNodes, prevNodes = prevNodes) - } - } -} - -data class StopStub(val name: String, val code: String, val zone: String, val onDemand: Boolean) { - companion object { - fun unmarshall(stream: InputStream): StopStub { - val reader = Reader(stream) - return StopStub( - code = reader.readString(), - name = reader.readString(), - zone = reader.readString(), - onDemand = reader.readBoolean() - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt b/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt new file mode 100644 index 0000000000000000000000000000000000000000..f99673af949bfcf97a51726de147d4a816d77846 --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt @@ -0,0 +1,163 @@ +package ml.adamsprogs.bimba.api + +import android.util.Log +import xyz.apiote.fruchtfleisch.Reader +import java.io.InputStream + +interface Item + +data class Stop( + val code: String, + val zone: String, + val position: String, + val changeOptions: List<ChangeOption>, + val name: String +) : Item { + override fun toString(): String { + var result = "$name ($code) [$zone] $position\n" + for (chOpt in changeOptions) + result += "${chOpt.line} → ${chOpt.headsign}\n" + return result + } + + companion object { + fun unmarshall(stream: InputStream): Stop { + val reader = Reader(stream) + val code = reader.readString() + val zone = reader.readString() + val position = reader.readString() + val chOptionsNum = reader.readUInt() + val changeOptions = mutableListOf<ChangeOption>() + for (i in 0UL until chOptionsNum) { + changeOptions.add(ChangeOption.unmarshall(stream)) + } + val name = reader.readString() + return Stop( + name = name, + code = code, + zone = zone, + position = position, + changeOptions = changeOptions + ) + } + } +} + +data class Line( + val textColour: Int, + val colour: Int, + val type: LineType, + val headsignsThere: List<String>, + val headsignsBack: List<String>, + val graphThere: LineGraph, + val graphBack: LineGraph, + val name: String +) : Item { + override fun toString(): String { + return "$name ($type) [$textColour/$colour]\n→ [${headsignsThere.joinToString()}]\n→ [${headsignsBack.joinToString()}]\n" + } + + companion object { + fun unmarshall(stream: InputStream): Line { + val reader = Reader(stream) + val textColour = reader.readInt().toInt() + val colour = reader.readInt().toInt() + val type = reader.readUInt() + val headsignsThereNum = reader.readUInt() + val headsignsThere = mutableListOf<String>() + for (i in 0UL until headsignsThereNum) { + headsignsThere.add(reader.readString()) + } + val headsignsBackNum = reader.readUInt() + val headsignsBack = mutableListOf<String>() + for (i in 0UL until headsignsBackNum) { + headsignsBack.add(reader.readString()) + } + val graphThere = LineGraph.unmarshall(stream) + val graphBack = LineGraph.unmarshall(stream) + val name = reader.readString() + return Line( + name = name, textColour = textColour, + colour = colour, type = LineType(type.toUInt()), headsignsThere = headsignsThere, + headsignsBack = headsignsBack, graphThere = graphThere, graphBack = graphBack + ) + } + } +} + +enum class LineType { + TRAM, BUS, UNKNOWN +} + +fun LineType(type: UInt): LineType { + Log.d("LineType", "$type") + return when (type) { + 0U -> LineType.valueOf("TRAM") + 3U -> LineType.valueOf("BUS") + else -> LineType.valueOf("UNKNOWN") + } +} + +data class ChangeOption(val line: String, val headsign: String) { + companion object { + fun unmarshall(stream: InputStream): ChangeOption { + val reader = Reader(stream) + return ChangeOption(line = reader.readString(), headsign = reader.readString()) + } + } +} + +data class LineGraph( + val stops: List<StopStub>, + val nextNodes: Map<Long, List<Long>>, + val prevNodes: Map<Long, List<Long>> +) { + companion object { + fun unmarshall(stream: InputStream): LineGraph { + val reader = Reader(stream) + val stopsNum = reader.readUInt() + val stops = mutableListOf<StopStub>() + for (i in 0UL until stopsNum) { + stops.add(StopStub.unmarshall(stream)) + } + val nextNodesNum = reader.readUInt() + val nextNodes = mutableMapOf<Long, List<Long>>() + for (i in 0UL until nextNodesNum) { + val from = reader.readInt() + val toNum = reader.readUInt() + val to = mutableListOf<Long>() + for (j in 0UL until toNum) { + to.add(reader.readInt()) + } + nextNodes[from] = to + } + val prevNodesNum = reader.readUInt() + val prevNodes = mutableMapOf<Long, List<Long>>() + for (i in 0UL until prevNodesNum) { + val from = reader.readInt() + val toNum = reader.readUInt() + val to = mutableListOf<Long>() + for (j in 0UL until toNum) { + to.add(reader.readInt()) + } + prevNodes[from] = to + } + + return LineGraph(stops = stops, nextNodes = nextNodes, prevNodes = prevNodes) + } + } +} + +data class StopStub(val name: String, val code: String, val zone: String, val onDemand: Boolean) { + companion object { + fun unmarshall(stream: InputStream): StopStub { + val reader = Reader(stream) + return StopStub( + code = reader.readString(), + name = reader.readString(), + zone = reader.readString(), + onDemand = reader.readBoolean() + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..5963e6ff2bfd57957699339564f7d6dec9890bb1 --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt @@ -0,0 +1,142 @@ +package ml.adamsprogs.bimba.dashboard + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.core.view.get +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.setupWithNavController +import com.google.android.material.bottomnavigation.BottomNavigationView +import ml.adamsprogs.bimba.R +import ml.adamsprogs.bimba.databinding.ActivityMainBinding +import ml.adamsprogs.bimba.search.ResultsActivity +import ml.adamsprogs.bimba.dashboard.ui.home.HomeFragment +import ml.adamsprogs.bimba.dashboard.ui.map.MapFragment +import ml.adamsprogs.bimba.dashboard.ui.voyage.VoyageFragment + + +class MainActivity : AppCompatActivity() { + + private lateinit var binding: ActivityMainBinding + private lateinit var locationPermissionRequest: ActivityResultLauncher<Array<String>> + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + supportFragmentManager.registerFragmentLifecycleCallbacks( + object : FragmentLifecycleCallbacks() { + override fun onFragmentViewCreated( + fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle? + ) { + setNavbarIcons(f) + super.onFragmentViewCreated(fm, f, v, savedInstanceState) + } + }, true + ) + + val navView: BottomNavigationView = binding.bottomNavigation + val navHostFragment = + supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment + val navController = navHostFragment.navController + navView.setupWithNavController(navController) + + locationPermissionRequest = registerForActivityResult( + ActivityResultContracts.RequestMultiplePermissions() + ) { permissions -> + when { + permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: false || + permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false -> { + showResults(ResultsActivity.Mode.MODE_LOCATION) + } + else -> { + Toast.makeText(this, "No location access given", Toast.LENGTH_SHORT).show() + } + } + } + } + + override fun onBackPressed() { + if (binding.container.isDrawerOpen(binding.navigationDrawer)) { + binding.container.closeDrawer(binding.navigationDrawer) + } else { + super.onBackPressed() + } + } + + fun onNavigationClicked() { + if (binding.container.isDrawerOpen(binding.navigationDrawer)) { + binding.container.closeDrawer(binding.navigationDrawer) + } else { + binding.container.openDrawer(binding.navigationDrawer) + } + } + + fun onGpsClicked(fab: View) { + + when (PackageManager.PERMISSION_GRANTED) { + ContextCompat.checkSelfPermission( + this, + Manifest.permission.ACCESS_COARSE_LOCATION + ) -> { + /* todo animation + https://developer.android.com/guide/fragments/animate + https://github.com/raheemadamboev/fab-explosion-animation-app + */ + showResults(ResultsActivity.Mode.MODE_LOCATION) + } + else -> { + locationPermissionRequest.launch( + arrayOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + ) + ) + } + } + } + + fun onSearchClicked(text: CharSequence?) { + showResults(ResultsActivity.Mode.MODE_SEARCH, text.toString()) + } + + private fun showResults(mode: ResultsActivity.Mode, query: String = "") { + val intent = Intent(this, ResultsActivity::class.java).apply { + putExtra("mode", mode) + putExtra("query", query) + } + startActivity(intent) + } + + private fun setNavbarIcons(f: Fragment) { + binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_outline_24dp) + binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_outline_24dp) + binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_outline_24dp) + when (f) { + is HomeFragment -> { + binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp) + } + is VoyageFragment -> { + binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_black_24dp) + } + is MapFragment -> { + binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_black_24dp) + } + else -> { + binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..744d3b43f1476c3916ee2fd2a3e48920efe4cf9f --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeFragment.kt @@ -0,0 +1,98 @@ +package ml.adamsprogs.bimba.dashboard.ui.home + +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import com.mancj.materialsearchbar.MaterialSearchBar +import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_NAVIGATION +import ml.adamsprogs.bimba.search.BimbaSuggestionsAdapter +import ml.adamsprogs.bimba.dashboard.MainActivity +import ml.adamsprogs.bimba.api.Item +import ml.adamsprogs.bimba.databinding.FragmentHomeBinding + +class HomeFragment : Fragment() { + + private var _binding: FragmentHomeBinding? = null + + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val homeViewModel = + ViewModelProvider(this)[HomeViewModel::class.java] + + _binding = FragmentHomeBinding.inflate(inflater, container, false) + val root: View = binding.root + + binding.searchBar.lastSuggestions = listOf<Item>() + homeViewModel.items.observe(viewLifecycleOwner) { + binding.searchBar.updateLastSuggestions(it.take(6)) // xxx workaround for suggestions behind navbar; should be paginated server-side + } + binding.searchBar.addTextChangeListener(SearchBarWatcher(homeViewModel)) + binding.searchBar.setOnSearchActionListener(object : MaterialSearchBar.OnSearchActionListener { + override fun onButtonClicked(buttonCode: Int) { + when (buttonCode) { + BUTTON_NAVIGATION -> { + (context as MainActivity).onNavigationClicked() + } + } + } + + override fun onSearchStateChanged(enabled: Boolean) { + } + + override fun onSearchConfirmed(text: CharSequence?) { + binding.searchBar.clearSuggestions() + (context as MainActivity).onSearchClicked(text) + } + }) + binding.searchBar.setCardViewElevation(0) + binding.searchBar.setCustomSuggestionAdapter(BimbaSuggestionsAdapter(layoutInflater, context){ + TODO("On click suggestion") + }) + + binding.floatingActionButton.setOnClickListener { + binding.searchBar.clearSuggestions() + (context as MainActivity).onGpsClicked(it) + } + // todo on suggestion click go to line or stop + // todo on searchbar focus && if != '' -> populate suggestions + + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} + +class SearchBarWatcher(private val homeViewModel: HomeViewModel) : TextWatcher { + private val handler = Handler(Looper.getMainLooper()) + private var workRunnable = Runnable {} + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + } + + override fun afterTextChanged(s: Editable?) { + handler.removeCallbacks(workRunnable) + workRunnable = Runnable { + val text = s.toString() + homeViewModel.getItems(text) + } + handler.postDelayed(workRunnable, 1000) // todo make good time (probably between 500, 1000ms) + } +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..48254fc128da6829a73a41991af55f70db50b0be --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeViewModel.kt @@ -0,0 +1,46 @@ +package ml.adamsprogs.bimba.dashboard.ui.home + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import ml.adamsprogs.bimba.api.* +import java.io.InputStream + +class HomeViewModel : ViewModel() { + + private val mutableItems = MutableLiveData<List<Item>>() + val items: LiveData<List<Item>> = mutableItems + + fun getItems(query: String) { + viewModelScope.launch { + val itemsStream = queryItems(query) + mutableItems.value = unmarshallItemResponse(itemsStream) + } + } + + private suspend fun unmarshallItemResponse(stream: InputStream): List<Item> { + return withContext(Dispatchers.IO) { + when (val response = ItemsResponse.unmarshall(stream)) { + is ItemsSuccess -> { + return@withContext response.items + } + else -> { + TODO("Error response") + } + } + } + } + + private fun String.printable() = map { + when (Character.getType(it).toByte()) { + Character.CONTROL, Character.FORMAT, Character.PRIVATE_USE, + Character.SURROGATE, Character.UNASSIGNED, Character.OTHER_SYMBOL + -> "\\u%04x".format(it.code) + else -> it.toString() + } + }.joinToString("") +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..5088bd52954aa7946746eca869c2ed21dc03647e --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapFragment.kt @@ -0,0 +1,42 @@ +package ml.adamsprogs.bimba.dashboard.ui.map + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import ml.adamsprogs.bimba.databinding.FragmentMapBinding + +class MapFragment : Fragment() { + + private var _binding: FragmentMapBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val mapViewModel = + ViewModelProvider(this).get(MapViewModel::class.java) + + _binding = FragmentMapBinding.inflate(inflater, container, false) + val root: View = binding.root + + val textView: TextView = binding.textNotifications + mapViewModel.text.observe(viewLifecycleOwner) { + textView.text = it + } + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..f811e9b19b6ffd84189117f0c2e1e04114a79f61 --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapViewModel.kt @@ -0,0 +1,13 @@ +package ml.adamsprogs.bimba.dashboard.ui.map + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class MapViewModel : ViewModel() { + + private val _text = MutableLiveData<String>().apply { + value = "This is notifications Fragment" + } + val text: LiveData<String> = _text +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..0a610b07b30f546c98f712b8aea6584b9e06a094 --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageFragment.kt @@ -0,0 +1,42 @@ +package ml.adamsprogs.bimba.dashboard.ui.voyage + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import ml.adamsprogs.bimba.databinding.FragmentVoyageBinding + +class VoyageFragment : Fragment() { + + private var _binding: FragmentVoyageBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val voyageViewModel = + ViewModelProvider(this)[VoyageViewModel::class.java] + + _binding = FragmentVoyageBinding.inflate(inflater, container, false) + val root: View = binding.root + + val textView: TextView = binding.textDashboard + voyageViewModel.text.observe(viewLifecycleOwner) { + textView.text = it + } + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..5348f5356cbc3108ab63a8f2980936d1e7409d5b --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageViewModel.kt @@ -0,0 +1,13 @@ +package ml.adamsprogs.bimba.dashboard.ui.voyage + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class VoyageViewModel : ViewModel() { + + private val _text = MutableLiveData<String>().apply { + value = "This is dashboard Fragment" + } + val text: LiveData<String> = _text +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..299c9d06176c355fa85f0baacc6a124817d232b2 --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt @@ -0,0 +1,21 @@ +package ml.adamsprogs.bimba.departures + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import ml.adamsprogs.bimba.databinding.ActivityDeparturesBinding + +class DeparturesActivity : AppCompatActivity() { + private var _binding: ActivityDeparturesBinding? = null + + private val binding get() = _binding!! + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + _binding = ActivityDeparturesBinding.inflate(layoutInflater) + setContentView(binding.root) + +// setSupportActionBar(binding.departuresAppBar) +// supportActionBar?.title = "Półwiejska" + binding.collapsingLayout.title = "Very long stop name that should span over multpile lines" // intent?.extras?.getString("name") + } +} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeFragment.kt deleted file mode 100644 index cc0dadedf1b16914aa539554619a9d7400348e3a..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeFragment.kt +++ /dev/null @@ -1,91 +0,0 @@ -package ml.adamsprogs.bimba.ui.home - -import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.text.Editable -import android.text.TextWatcher -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import com.mancj.materialsearchbar.MaterialSearchBar -import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_BACK -import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_NAVIGATION -import ml.adamsprogs.bimba.MainActivity -import ml.adamsprogs.bimba.R -import ml.adamsprogs.bimba.databinding.FragmentHomeBinding - -class HomeFragment : Fragment() { - - private var _binding: FragmentHomeBinding? = null - - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val homeViewModel = - ViewModelProvider(this)[HomeViewModel::class.java] - - _binding = FragmentHomeBinding.inflate(inflater, container, false) - val root: View = binding.root - - binding.searchBar.lastSuggestions = listOf<String>() - homeViewModel.text.observe(viewLifecycleOwner) { - binding.searchBar.updateLastSuggestions(it.take(6)) // xxx workaround for suggestions behind navbar; should be paginated server-side - } - binding.searchBar.addTextChangeListener(SearchBarWatcher(homeViewModel)) - binding.searchBar.setOnSearchActionListener(object : MaterialSearchBar.OnSearchActionListener { - override fun onButtonClicked(buttonCode: Int) { - when (buttonCode) { - BUTTON_NAVIGATION -> { - (context as MainActivity).onNavigationClicked() - } - } - } - - override fun onSearchStateChanged(enabled: Boolean) { - } - - override fun onSearchConfirmed(text: CharSequence?) { - // todo on search show results activity with more results - } - }) - binding.searchBar.setCardViewElevation(0) - // todo on suggestion click go to line or stop - // todo adapter for suggestions - - // todo gps button in fab (with animation https://stackoverflow.com/questions/68663679/how-to-transform-the-floating-action-buttons-to-full-screen-and-open-new-activit https://codesnipps.simolation.com/post/android/create-circular-reveal-animation-when-starting-activitys/) - - return root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} - -class SearchBarWatcher(private val homeViewModel: HomeViewModel) : TextWatcher { - private val handler = Handler(Looper.getMainLooper()) - private var workRunnable = Runnable {} - - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { - } - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - } - - override fun afterTextChanged(s: Editable?) { - handler.removeCallbacks(workRunnable) - workRunnable = Runnable { - val text = s.toString() - homeViewModel.getItems(text) - } - handler.postDelayed(workRunnable, 1000) // todo make good time (probably between 500, 1000ms) - } -} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeViewModel.kt deleted file mode 100644 index 5a654f6bddceac3fb8d1d26380a392f6a03f1f7c..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeViewModel.kt +++ /dev/null @@ -1,83 +0,0 @@ -package ml.adamsprogs.bimba.ui.home - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import ml.adamsprogs.bimba.api.Line -import ml.adamsprogs.bimba.api.Stop -import xyz.apiote.fruchtfleisch.Reader -import java.io.InputStream -import java.net.HttpURLConnection -import java.net.URL - -class HomeViewModel : ViewModel() { - - private val _text = MutableLiveData<List<String>>() - val text: LiveData<List<String>> = _text - - fun getItems(query: String) { - viewModelScope.launch { - val itemsStream = queryItems(query) - _text.value = unmarshallItemResponse(itemsStream) - } - } - - @Suppress("BlockingMethodInNonBlockingContext") - private suspend fun queryItems(query: String): InputStream { - return withContext(Dispatchers.IO) { - val url = URL("https://bimba.apiote.xyz/api/poznan_ztm/items?q=${query}") - val c = (url.openConnection() as HttpURLConnection).apply { - setRequestProperty("X-Bimba-Token", "ef0179272e7270e1a2da1710a8ba24e1") - } - c.inputStream - } - } - - private suspend fun unmarshallItemResponse(r: InputStream): List<String> { - val items = mutableListOf<String>() - val reader = Reader(r) - withContext(Dispatchers.IO) { - // todo ItemResponse from .api.unmarshallItemResponse(stream) - when (reader.readUInt()) { - 0UL -> { - TODO("error response") - } - 1UL -> { - val itemsNum = reader.readUInt() - for (i in 0UL until itemsNum) { - when (reader.readUInt()) { - 0UL -> { - val stop = Stop.unmarshall(r) - items.add(stop.toString()) - } - 1UL -> { - val line = Line.unmarshall(r) - items.add(line.toString()) - } - else -> { - TODO("throw unknown tag") - } - } - } - } - else -> { - TODO("throw unknown tag") - } - } - } - return items - } - - private fun String.printable() = map { - when (Character.getType(it).toByte()) { - Character.CONTROL, Character.FORMAT, Character.PRIVATE_USE, - Character.SURROGATE, Character.UNASSIGNED, Character.OTHER_SYMBOL - -> "\\u%04x".format(it.code) - else -> it.toString() - } - }.joinToString("") -} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapFragment.kt deleted file mode 100644 index 5600d90bfca6343124171f020138f196213fd3d2..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package ml.adamsprogs.bimba.ui.map - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import ml.adamsprogs.bimba.databinding.FragmentMapBinding - -class MapFragment : Fragment() { - - private var _binding: FragmentMapBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val mapViewModel = - ViewModelProvider(this).get(MapViewModel::class.java) - - _binding = FragmentMapBinding.inflate(inflater, container, false) - val root: View = binding.root - - val textView: TextView = binding.textNotifications - mapViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapViewModel.kt deleted file mode 100644 index f754ec2f19f3586f8ce460242021c16cf105dcc6..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapViewModel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package ml.adamsprogs.bimba.ui.map - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class MapViewModel : ViewModel() { - - private val _text = MutableLiveData<String>().apply { - value = "This is notifications Fragment" - } - val text: LiveData<String> = _text -} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageFragment.kt deleted file mode 100644 index e8985169ac60d3e4e9e2276cbf41fedbf043d652..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package ml.adamsprogs.bimba.ui.voyage - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import ml.adamsprogs.bimba.databinding.FragmentVoyageBinding - -class VoyageFragment : Fragment() { - - private var _binding: FragmentVoyageBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val voyageViewModel = - ViewModelProvider(this).get(VoyageViewModel::class.java) - - _binding = FragmentVoyageBinding.inflate(inflater, container, false) - val root: View = binding.root - - val textView: TextView = binding.textDashboard - voyageViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageViewModel.kt deleted file mode 100644 index fe98671efbb3b5a93df99e9e8b6086dcdf592dc3..0000000000000000000000000000000000000000 --- a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageViewModel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package ml.adamsprogs.bimba.ui.voyage - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class VoyageViewModel : ViewModel() { - - private val _text = MutableLiveData<String>().apply { - value = "This is dashboard Fragment" - } - val text: LiveData<String> = _text -} \ No newline at end of file diff --git a/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt b/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt index ca86beb025fe7110395f2cf2dbbab391fe154c32..cf700941c0f505541b2e818365e5535880ba7fa1 100644 --- a/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt +++ b/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt @@ -1,5 +1,6 @@ package xyz.apiote.fruchtfleisch +import java.io.DataInputStream import java.io.EOFException import java.io.InputStream @@ -41,6 +42,38 @@ if (b < 0) { throw EOFException("while reading byte") } return b.toUByte() + } + + fun readU16(): UShort { + var result = 0U + for (i in 0 until 2) { + result = result or (readU8().toUInt().shl(2U.shl(i).toInt())) + } + return result.toUShort() + } + + fun readU32(): UInt { + var result = 0U + for (i in 0 until 4) { + result = result or (readU8().toUInt().shl(2U.shl(i).toInt())) + } + return result + } + + fun readU64(): UShort { + var result = 0U + for (i in 0 until 8) { + result = result or (readU8().toUInt().shl(2U.shl(i).toInt())) + } + return result.toUShort() + } + + fun readFloat32(): Float { + return DataInputStream(stream).readFloat() + } + + fun readFloat64(): Double { + return DataInputStream(stream).readDouble() } fun readData(length: UByte): ByteArray { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4a5f76c9c20ed397738fa3d24da0f99c491f63cc..7f7d3e77bd7b60502b44ff3b2124ab5ee5b11d6a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,13 +3,24 @@xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/container" android:layout_width="match_parent" - android:layout_height="match_parent" - android:fitsSystemWindows="true"> + android:layout_height="match_parent"> <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> + <com.google.android.material.appbar.AppBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fitsSystemWindows="true"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/topAppBar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + app:title="" /> + </com.google.android.material.appbar.AppBarLayout> + <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> @@ -19,7 +30,6 @@ android:id="@+id/nav_host_fragment_activity_main" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="0dp" - android:background="?attr/colorSurfaceVariant" app:defaultNavHost="true" app:layout_constraintBottom_toTopOf="@+id/bottom_navigation" app:layout_constraintEnd_toEndOf="parent" @@ -29,12 +39,9 @@ app:navGraph="@navigation/front_navigation" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_navigation" - style="@style/Theme.Bimba.BottomNavigationHome" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" - android:background="?attr/colorSurfaceVariant" - app:elevation="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 56a9aa247c61445bc3140065c58bd1e84a79433a..675e138c356b890370f573bc063ca633a057d41c 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -5,7 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:tag="@string/title_home" - tools:context=".ui.home.HomeFragment"> + tools:context=".dashboard.ui.home.HomeFragment"> <com.mancj.materialsearchbar.MaterialSearchBar android:id="@+id/search_bar" diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml index 74641967c4e169cbca457bc48e5908d06af70dda..619f8762a446d4a9644c88b56e08a217d00f7021 100644 --- a/app/src/main/res/layout/fragment_map.xml +++ b/app/src/main/res/layout/fragment_map.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.map.MapFragment"> + tools:context=".dashboard.ui.map.MapFragment"> <TextView android:id="@+id/text_notifications" diff --git a/app/src/main/res/layout/fragment_voyage.xml b/app/src/main/res/layout/fragment_voyage.xml index 552c359b898a7818990b8fd4ea6923eae8281c63..693d09e63f0b540012e227ccea8a0e423536bc04 100644 --- a/app/src/main/res/layout/fragment_voyage.xml +++ b/app/src/main/res/layout/fragment_voyage.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.voyage.VoyageFragment"> + tools:context=".dashboard.ui.voyage.VoyageFragment"> <TextView android:id="@+id/text_dashboard" diff --git a/app/src/main/res/navigation/front_navigation.xml b/app/src/main/res/navigation/front_navigation.xml index 6b50b81c3dfbb3fdbcc18789ece45ed9cc4a5afb..dc19c6dec415f9646646d2413ec7d19cf1d015d9 100644 --- a/app/src/main/res/navigation/front_navigation.xml +++ b/app/src/main/res/navigation/front_navigation.xml @@ -7,19 +7,19 @@ app:startDestination="@+id/navigation_home"> <fragment android:id="@+id/navigation_home" - android:name="ml.adamsprogs.bimba.ui.home.HomeFragment" + android:name="ml.adamsprogs.bimba.dashboard.ui.home.HomeFragment" android:label="@string/title_home" tools:layout="@layout/fragment_home" /> <fragment android:id="@+id/navigation_map" - android:name="ml.adamsprogs.bimba.ui.map.MapFragment" + android:name="ml.adamsprogs.bimba.dashboard.ui.map.MapFragment" android:label="@string/title_map" tools:layout="@layout/fragment_map" /> <fragment android:id="@+id/navigation_voyage" - android:name="ml.adamsprogs.bimba.ui.voyage.VoyageFragment" + android:name="ml.adamsprogs.bimba.dashboard.ui.voyage.VoyageFragment" android:label="@string/title_voyage" tools:layout="@layout/fragment_voyage" /> </navigation> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9709dbbc1bbf18b1a4bab9aa575086a2e772ebee..f97ef3c2999011ce6ec1fb2f90423320f52b6444 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,4 +6,5 @@ Voyage <string name="searchbar_menu_item_gps">search by GPS</string> <string name="home_fab_description">GPS icon</string> <string name="search_placeholder">Search stops and lines</string> + <string name="title_activity_results">Results</string> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 5332ac581520f04157c890c6d5af752e20eaaf38..1081689f25ee509ba58eaf887a6f8e114bc3aba5 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,4 +1,4 @@ -<resources> +<resources xmlns:tools="http://schemas.android.com/tools"> <style name="Theme.Bimba" parent="Theme.Material3.Light.NoActionBar"> <item name="android:fontFamily">@font/railway</item> @@ -28,7 +28,10 @@- @color/md_theme_light_outline
<item name="colorOnSurfaceInverse">@color/md_theme_light_inverseOnSurface</item> <item name="colorSurfaceInverse">@color/md_theme_light_inverseSurface</item> <item name="colorPrimaryInverse">@color/md_theme_light_inversePrimary</item> - <item name="statusBarBackground">@color/md_theme_light_surfaceVariant</item> + + <item name="statusBarBackground">@android:color/transparent</item> + <item name="android:statusBarColor">@android:color/transparent</item> + <item name="android:enforceStatusBarContrast" tools:targetApi="q">false</item> <item name="lightStatusBar">true</item> </style> @@ -36,18 +39,26 @@<attr name="lightStatusBar" format="boolean" /> </declare-styleable> - <style name="Theme.Bimba.BottomNavigationHome" parent="Widget.Material3.BottomNavigationView"> - <item name="materialThemeOverlay">@style/ThemeOverlay.App.BottomNavigationView</item> + <style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight"> + <item name="mt_searchBarColor">@color/md_theme_light_surfaceVariant</item> + <item name="mt_textColor">@color/md_theme_light_onSurfaceVariant</item> + <item name="mt_placeholderColor">@color/md_theme_light_onSurfaceVariant + </item> <!-- todo grey out --> + <item name="mt_backIconTint">@color/md_theme_light_onSurfaceVariant</item> + <item name="mt_navIconTint">@color/md_theme_light_onSurfaceVariant</item> + <item name="mt_searchIconTint">@color/md_theme_light_onSurfaceVariant</item> + <item name="mt_menuIconTint">@color/md_theme_light_onSurfaceVariant</item> + <item name="mt_clearIconTint">@color/md_theme_light_onSurfaceVariant</item> </style> - <style name="ThemeOverlay.App.BottomNavigationView" parent=""> - <item name="colorSurface">@color/md_theme_light_surface</item> - <item name="colorOnSurfaceVariant">@color/md_theme_light_onSurfaceVariant</item> + <style name="Theme.Bimba.SearchResult.Title" parent="Theme.Bimba"> + <item name="android:textColor">@color/md_theme_light_onSurfaceVariant</item> + <item name="android:textSize">16sp</item> </style> - <style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight"> - <item name="mt_searchBarColor">@color/md_theme_light_surface</item> - <item name="mt_textColor">@color/md_theme_light_onSurface</item> - <item name="mt_placeholderColor">@color/md_theme_light_onSurface</item> <!-- todo grey out --> + <style name="Theme.Bimba.SearchResult.Description" parent="Theme.Bimba"> + <item name="android:textColor">@color/md_theme_light_onSurfaceVariant + </item> <!-- todo grey out --> + <item name="android:textSize">9sp</item> </style> </resources> \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index d13d41607cf84742d49707dfbad0c1eab0f5b2ed..4d90afca85cd7032c4dd5c0c74b619a01f11385d 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -1,4 +1,4 @@ -<resources> +<resources xmlns:tools="http://schemas.android.com/tools"> <style name="Theme.Bimba" parent="Theme.Material3.Dark.NoActionBar"> <item name="android:fontFamily">@font/railway</item> @@ -28,7 +28,10 @@ - @color/md_theme_dark_outline
<item name="colorOnSurfaceInverse">@color/md_theme_dark_inverseOnSurface</item> <item name="colorSurfaceInverse">@color/md_theme_dark_inverseSurface</item> <item name="colorPrimaryInverse">@color/md_theme_dark_inversePrimary</item> - <item name="statusBarBackground">@color/md_theme_dark_surfaceVariant</item> + + <item name="statusBarBackground">@android:color/transparent</item> + <item name="android:statusBarColor">@android:color/transparent</item> + <item name="android:enforceStatusBarContrast" tools:targetApi="q">false</item> <item name="lightStatusBar">false</item> </style> @@ -36,18 +39,24 @@<attr name="lightStatusBar" format="boolean" /> </declare-styleable> - <style name="Theme.Bimba.BottomNavigationHome" parent="Widget.Material3.BottomNavigationView"> - <item name="materialThemeOverlay">@style/ThemeOverlay.App.BottomNavigationView</item> + <style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight"> + <item name="mt_searchBarColor">@color/md_theme_dark_surfaceVariant</item> + <item name="mt_textColor">@color/md_theme_dark_onSurfaceVariant</item> + <item name="mt_placeholderColor">@color/md_theme_dark_onSurfaceVariant</item> <!-- todo grey out --> + <item name="mt_backIconTint">@color/md_theme_dark_onSurfaceVariant</item> + <item name="mt_navIconTint">@color/md_theme_dark_onSurfaceVariant</item> + <item name="mt_searchIconTint">@color/md_theme_dark_onSurfaceVariant</item> + <item name="mt_menuIconTint">@color/md_theme_dark_onSurfaceVariant</item> + <item name="mt_clearIconTint">@color/md_theme_dark_onSurfaceVariant</item> </style> - <style name="ThemeOverlay.App.BottomNavigationView" parent=""> - <item name="colorSurface">@color/md_theme_dark_surface</item> - <item name="colorOnSurfaceVariant">@color/md_theme_dark_onSurfaceVariant</item> + <style name="Theme.Bimba.SearchResult.Title" parent="Theme.Bimba"> + <item name="android:textColor">@color/md_theme_dark_onSurfaceVariant</item> + <item name="android:textSize">16sp</item> </style> - <style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight"> - <item name="mt_searchBarColor">@color/md_theme_dark_surface</item> - <item name="mt_textColor">@color/md_theme_dark_onSurface</item> - <item name="mt_placeholderColor">@color/md_theme_dark_onSurface</item> <!-- todo grey out --> + <style name="Theme.Bimba.SearchResult.Description" parent="Theme.Bimba"> + <item name="android:textColor">@color/md_theme_dark_onSurfaceVariant</item> <!-- todo grey out --> + <item name="android:textSize">9sp</item> </style> </resources> \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7565e1c021f5cfdfd7e0b5c751720cfb9f9f89d7..64f119e33344ef7caf3fa99959245374a5436294 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id 'com.android.application' version '7.2.2' apply false id 'com.android.library' version '7.2.2' apply false - id 'org.jetbrains.kotlin.android' version '1.6.10' apply false + id 'org.jetbrains.kotlin.android' version '1.7.10' apply false } task clean(type: Delete) {