Author: Adam Pioterek <adam.pioterek@protonmail.ch>
refresh stops on main activity
app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt | 85 ++++- app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt | 5 app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt | 20 app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt | 23 + app/src/main/res/layout/activity_main.xml | 53 ++- app/src/main/res/values-pl/strings.xml | 8 app/src/main/res/values/strings.xml | 9
diff --git a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt index 4040505398c178bba2b0bde1bfc4ecbc381431dc..bfc9c3d3ae32ab816dbcf8aa000f8bfd6e43bd5f 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt @@ -4,55 +4,52 @@ import android.content.Intent import android.content.IntentFilter import android.os.* import android.support.design.widget.Snackbar -import android.support.v7.app.AppCompatActivity -import android.support.v7.app.AppCompatDelegate +import android.support.v7.app.* import android.text.Html import android.view.View import com.arlib.floatingsearchview.FloatingSearchView import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion -import ml.adamsprogs.bimba.models.StopSuggestion -import ml.adamsprogs.bimba.models.Timetable +import ml.adamsprogs.bimba.models.* import kotlin.concurrent.thread import android.app.Activity +import android.content.Context +import android.support.v4.widget.SwipeRefreshLayout +import android.util.Log import android.view.inputmethod.InputMethodManager -class MainActivity : AppCompatActivity(), MessageReceiver.OnTimetableDownloadListener { - val listener = this - val receiver = MessageReceiver() - lateinit var layout: View +class MainActivity : AppCompatActivity(), MessageReceiver.OnTimetableDownloadListener, SwipeRefreshLayout.OnRefreshListener { + val context: Context = this + val receiver = MessageReceiver() lateinit var timetable: Timetable var stops: ArrayList<StopSuggestion>? = null + lateinit var swipeRefreshLayout: SwipeRefreshLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO) - layout = findViewById(R.id.main_layout) - val context = this + prepareSwipeLayout() + + prepareOnDownloadListener() + startDownloaderService() - val filter = IntentFilter("ml.adamsprogs.bimba.timetableDownloaded") - filter.addCategory(Intent.CATEGORY_DEFAULT) - registerReceiver(receiver, filter) - receiver.addOnTimetableDownloadListener(listener) - startService(Intent(context, TimetableDownloader::class.java)) + getStops() - timetable = Timetable(this) - stops = timetable.getStops() val searchView = findViewById(R.id.search_view) as FloatingSearchView searchView.setOnQueryChangeListener({ _, newQuery -> thread { val newStops = stops!!.filter { deAccent(it.body.split("\n")[0]).contains(newQuery, true) } - runOnUiThread { searchView.swapSuggestions (newStops)} + runOnUiThread { searchView.swapSuggestions(newStops) } } }) searchView.setOnSearchListener(object : FloatingSearchView.OnSearchListener { override fun onSuggestionClicked(searchSuggestion: SearchSuggestion) { val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager - var view = context.currentFocus + var view = (context as MainActivity).currentFocus if (view == null) { view = View(context) } @@ -61,6 +58,7 @@ intent = Intent(context, StopActivity::class.java) intent.putExtra("stop", (searchSuggestion as StopSuggestion).id) startActivity(intent) } + override fun onSearchAction(query: String) { } }) @@ -70,19 +68,48 @@ val suggestion = item as StopSuggestion val text = suggestion.body.split("\n") val t = "<small><font color=\"#a0a0a0\">" + text[1] + "</font></small>" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - textView.text = Html.fromHtml(text[0]+"<br/>"+t, Html.FROM_HTML_MODE_LEGACY) + textView.text = Html.fromHtml(text[0] + "<br/>" + t, Html.FROM_HTML_MODE_LEGACY) } else { @Suppress("DEPRECATION") - textView.text = Html.fromHtml(text[0]+"<br/>"+t) + textView.text = Html.fromHtml(text[0] + "<br/>" + t) } } //todo searchView.attachNavigationDrawerToMenuButton(mDrawerLayout) } + private fun getStops() { + timetable = Timetable(this) + stops = timetable.getStops() + } + + private fun prepareOnDownloadListener() { + val filter = IntentFilter("ml.adamsprogs.bimba.timetableDownloaded") + filter.addCategory(Intent.CATEGORY_DEFAULT) + registerReceiver(receiver, filter) + receiver.addOnTimetableDownloadListener(context as MessageReceiver.OnTimetableDownloadListener) + } + + private fun startDownloaderService() { + startService(Intent(context, TimetableDownloader::class.java)) + } + + private fun prepareSwipeLayout() { + swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout) as SwipeRefreshLayout + swipeRefreshLayout.isEnabled = true + swipeRefreshLayout.setOnRefreshListener(this) + swipeRefreshLayout.setColorSchemeResources(R.color.colorAccent, R.color.colorPrimary) + } + + override fun onRefresh() { + swipeRefreshLayout.isRefreshing = true + Log.i("Refresh", "Downloading") + startDownloaderService() + } + override fun onDestroy() { super.onDestroy() - receiver.removeOnTimetableDownloadListener(listener) + receiver.removeOnTimetableDownloadListener(context as MessageReceiver.OnTimetableDownloadListener) unregisterReceiver(receiver) } @@ -99,9 +126,19 @@ result = result.replace('ń', 'n') return result } - override fun onTimetableDownload() { + override fun onTimetableDownload(result: String?) { + Log.i("Refresh", "downloaded: $result") + val message: String + when (result) { + "downloaded" -> message = getString(R.string.timetable_downloaded) + "no connectivity" -> message = getString(R.string.no_connectivity) + "up-to-date" -> message = getString(R.string.timetable_up_to_date) + "validity failed" -> message = getString(R.string.validity_failed) + else -> message = getString(R.string.error_try_later) + } timetable.refresh() stops = timetable.getStops() - Snackbar.make(layout, getString(R.string.timetable_downloaded), Snackbar.LENGTH_LONG).show() + Snackbar.make(swipeRefreshLayout, message, Snackbar.LENGTH_LONG).show() + swipeRefreshLayout.isRefreshing = false } } diff --git a/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt b/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt index 4e2c81f4ef4cb432099ea2c7d7733b1ccc833583..0203994b9671acb43fbc21958b3f3800de22dd4a 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt @@ -8,8 +8,9 @@ class MessageReceiver: BroadcastReceiver() { val onTimetableDownloadListeners: HashSet<OnTimetableDownloadListener> = HashSet() override fun onReceive(context: Context?, intent: Intent?) { + val result = intent?.getStringExtra("result") for (listener in onTimetableDownloadListeners) { - listener.onTimetableDownload() + listener.onTimetableDownload(result) } } @@ -22,6 +23,6 @@ onTimetableDownloadListeners.remove(listener) } interface OnTimetableDownloadListener { - fun onTimetableDownload() + fun onTimetableDownload(result: String?) } } \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt index 177140d77dbe6c1a5c8a66e159318a03b6cd7ae1..8b31c19d7a91d7e5552a76bbb774cff692b123f1 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt @@ -11,6 +11,7 @@ class NoDbActivity : AppCompatActivity(), NetworkStateReceiver.OnConnectivityChangeListener, MessageReceiver.OnTimetableDownloadListener { val networkStateReceiver = NetworkStateReceiver() val timetableDownloadReceiver = MessageReceiver() var serviceRunning = false + var askedForNetwork = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -22,6 +23,7 @@ registerReceiver(timetableDownloadReceiver, filter) timetableDownloadReceiver.addOnTimetableDownloadListener(this) if (!isNetworkAvailable(this)) { + askedForNetwork = true (findViewById(R.id.noDbCaption) as TextView).text = getString(R.string.no_db_connect) filter = IntentFilter("android.net.conn.CONNECTIVITY_CHANGE") registerReceiver(networkStateReceiver, filter) @@ -45,16 +47,22 @@ /*if (!connected) serviceRunning = false*/ } - override fun onTimetableDownload() { - timetableDownloadReceiver.removeOnTimetableDownloadListener(this) - networkStateReceiver.removeOnConnectivityChangeListener(this) - startActivity(Intent(this, MainActivity::class.java)) - finish() + override fun onTimetableDownload(result: String?) { + when (result) { + "downloaded" -> { + timetableDownloadReceiver.removeOnTimetableDownloadListener(this) + networkStateReceiver.removeOnConnectivityChangeListener(this) + startActivity(Intent(this, MainActivity::class.java)) + finish() + } + else -> (findViewById(R.id.noDbCaption) as TextView).text = getString(R.string.error_try_later) + } } override fun onPause() { super.onPause() unregisterReceiver(timetableDownloadReceiver) - unregisterReceiver(networkStateReceiver) + if (askedForNetwork) + unregisterReceiver(networkStateReceiver) } } diff --git a/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt b/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt index b7187dcc8a173bb5893a41b4d6bbdbc31299adc7..f933bfbf80b424de1a383826236afad73e2cd5ec 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt @@ -23,8 +23,10 @@ if (intent != null) { notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val prefs = this.getSharedPreferences("ml.adamsprogs.bimba.prefs", Context.MODE_PRIVATE)!! - if (!isNetworkAvailable(this)) + if (!isNetworkAvailable(this)) { + sendResult("no connectivity") return + } val metadataUrl = URL("https://adamsprogs.ml/w/_media/programmes/bimba/timetable.db.meta") var httpCon = metadataUrl.openConnection() as HttpURLConnection if (httpCon.responseCode != HttpURLConnection.HTTP_OK) @@ -35,8 +37,10 @@ val lastModified = reader.readLine() val checksum = reader.readLine() size = Integer.parseInt(reader.readLine()) / 1024 val currentLastModified = prefs.getString("timetableLastModified", "1979-10-12T00:00") - if (lastModified <= currentLastModified && !intent.getBooleanExtra("force", false)) + if (lastModified <= currentLastModified && !intent.getBooleanExtra("force", false)) { + sendResult("up-to-date") return + } Log.i("Downloader", "timetable is newer ($lastModified > $currentLastModified)") notify(0) @@ -56,16 +60,22 @@ file.renameTo(File("timetable.db")) val prefsEditor = prefs.edit() prefsEditor.putString("timetableLastModified", lastModified) prefsEditor.apply() - val broadcastIntent = Intent() - broadcastIntent.action = "ml.adamsprogs.bimba.timetableDownloaded" - broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT) - sendBroadcast(broadcastIntent) + sendResult("downloaded") } else { Log.i("Downloader", "downloaded but is wrong") + sendResult("validity failed") } cancelNotification() } + } + + private fun sendResult(result: String) { + val broadcastIntent = Intent() + broadcastIntent.action = "ml.adamsprogs.bimba.timetableDownloaded" + broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT) + broadcastIntent.putExtra("result", result) + sendBroadcast(broadcastIntent) } private fun notify(progress: Int) { @@ -100,7 +110,6 @@ md.update(buf, 0, len) out.write(buf, 0, len) lenSum += len.toFloat() / 1024.0f notify(lenSum.toInt()) - Log.i("Downloader", "downloading $len B: $lenSum KiB") } out.close() } catch (e: Exception) { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 739666dc2ed00f729c50555a9a7681dd3ee1cce6..50db680552ef62dca20d5cf36e3e3e65aa3101db 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,21 +1,44 @@ <?xml version="1.0" encoding="utf-8"?> -<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" +<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="ml.adamsprogs.bimba.MainActivity" - android:id="@+id/main_layout"> - <com.arlib.floatingsearchview.FloatingSearchView - android:id="@+id/search_view" + tools:context="ml.adamsprogs.bimba.MainActivity"> + + <android.support.constraint.ConstraintLayout + android:id="@+id/main_layout" android:layout_width="match_parent" - android:layout_height="match_parent" - app:floatingSearch_searchBarMarginLeft="16dp" - app:floatingSearch_searchBarMarginTop="16dp" - app:floatingSearch_searchBarMarginRight="16dp" - app:floatingSearch_searchHint="Search..." - app:floatingSearch_suggestionsListAnimDuration="250" - app:floatingSearch_showSearchKey="false" - app:floatingSearch_leftActionMode="showHamburger" - app:floatingSearch_close_search_on_keyboard_dismiss="true"/> -</android.support.constraint.ConstraintLayout> + android:layout_height="match_parent"> + + <com.arlib.floatingsearchview.FloatingSearchView + android:id="@+id/search_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:floatingSearch_close_search_on_keyboard_dismiss="true" + app:floatingSearch_leftActionMode="showHamburger" + app:floatingSearch_searchBarMarginLeft="16dp" + app:floatingSearch_searchBarMarginRight="16dp" + app:floatingSearch_searchBarMarginTop="16dp" + app:floatingSearch_searchHint="@string/search_placeholder" + app:floatingSearch_showSearchKey="false" + app:floatingSearch_suggestionsListAnimDuration="250" /> + + + <android.support.v7.widget.RecyclerView + android:id="@+id/favouritesList" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scrollbars="none" + android:layout_marginTop="128dp" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + android:layout_marginStart="8dp" + app:layout_constraintEnd_toEndOf="parent" + android:layout_marginEnd="8dp" + app:layout_constraintBottom_toBottomOf="parent" + android:layout_marginBottom="8dp" /> + + </android.support.constraint.ConstraintLayout> +</android.support.v4.widget.SwipeRefreshLayout> \ 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 a56f3fca135b861588ef4cdbc093a4017ccc9e19..54b6e3bedc3affa2cc01ff48b8811d78aa25f21a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,8 +11,13 @@departure type (timetable, VM) <string name="departure_in">In %1$s minutes</string> <string name="departure_to">→ %1$s</string> <string name="departure_at">At %1$s</string> - <string name="no_database_background">no database background</string> + <string name="no_database_background" translatable="false">no database background</string> <string name="no_db_connect">Connect to the Internet to download the timetable</string> - <string name="no_db_downloading">Timetable is being downloaded</string> + <string name="no_db_downloading">Timetable is being downloaded…</string> <string name="timetable_downloading">Downloading timetable</string> + <string name="search_placeholder">Search…</string> + <string name="no_connectivity">No connectivity – can’t update timetable</string> + <string name="timetable_up_to_date">Timetable is up-to-date</string> + <string name="validity_failed">Downloaded timetable is corrupted – can’t update</string> + <string name="error_try_later">Error. Try again later</string> </resources> diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 0d3d7bccd9c2fa4b602dfce5e810aa190f7ef38c..2e69341c19dd00da266a34b134c8f252a79be450 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -9,4 +9,12 @@Typ <string name="departure_in">Za %1$s minut</string> <string name="departure_at">O %1$s</string> <string name="departure_to">→ %1$s</string> + <string name="no_db_connect">Połącz się z Internetem aby pobrać rozkład</string> + <string name="no_db_downloading">Pobieranie rozkładu…</string> + <string name="timetable_downloading">Pobieranie rozkładu…</string> + <string name="search_placeholder">Szukaj…</string> + <string name="timetable_up_to_date">Rozkład jest aktualny</string> + <string name="validity_failed">Pobrany rozkład jest uszkodzony – nie można zaktualizować</string> + <string name="no_connectivity">Brak połączenia z Internetem – nie można zaktualizować rozkładu</string> + <string name="error_try_later">Błąd. Spróbuj ponownie później</string> </resources> \ No newline at end of file