Author: Adam Pioterek <adam.pioterek@protonmail.ch>
Downloading timetable on first run
app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt | 12 app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt | 44 +++ app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt | 50 +++ app/src/main/java/ml/adamsprogs/bimba/SplashActivity.kt | 8 app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt | 43 ++ app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt | 45 ++- app/src/main/res/drawable/ic_download.xml | 9 app/src/main/res/drawable/nodb.xml | 70 +--- app/src/main/res/layout/activity_nodb.xml | 45 ++ app/src/main/res/values/strings.xml | 4
diff --git a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt index 8d14945fb0803008a88b8e924928ddb075b1423a..4040505398c178bba2b0bde1bfc4ecbc381431dc 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt @@ -18,8 +18,8 @@ import android.view.inputmethod.InputMethodManager class MainActivity : AppCompatActivity(), MessageReceiver.OnTimetableDownloadListener { - lateinit var listener: MessageReceiver.OnTimetableDownloadListener - lateinit var receiver: MessageReceiver + val listener = this + val receiver = MessageReceiver() lateinit var layout: View lateinit var timetable: Timetable var stops: ArrayList<StopSuggestion>? = null @@ -31,11 +31,9 @@ AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO) layout = findViewById(R.id.main_layout) val context = this - listener = this val filter = IntentFilter("ml.adamsprogs.bimba.timetableDownloaded") filter.addCategory(Intent.CATEGORY_DEFAULT) - receiver = MessageReceiver() registerReceiver(receiver, filter) receiver.addOnTimetableDownloadListener(listener) startService(Intent(context, TimetableDownloader::class.java)) @@ -43,12 +41,6 @@ timetable = Timetable(this) stops = timetable.getStops() val searchView = findViewById(R.id.search_view) as FloatingSearchView - - if (stops == null) { - //todo something more direct and create pull-to-refresh - Snackbar.make(layout, getString(R.string.no_timetable), Snackbar.LENGTH_LONG).show() - return - } searchView.setOnQueryChangeListener({ _, newQuery -> thread { diff --git a/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt b/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..cd17f1cdc5ed38f6452844e51000d72fdc21e380 --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt @@ -0,0 +1,44 @@ +package ml.adamsprogs.bimba + +import android.net.ConnectivityManager +import android.content.Intent +import android.content.BroadcastReceiver +import android.content.Context + +fun isNetworkAvailable(context: Context): Boolean { + val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val activeNetworkInfo = connectivityManager.activeNetworkInfo + return activeNetworkInfo != null && activeNetworkInfo.isConnected +} + +class NetworkStateReceiver : BroadcastReceiver() { + + val onConnectivityChangeListeners = HashSet<OnConnectivityChangeListener>() + + override fun onReceive(context: Context, intent: Intent) { + if (intent.extras != null) { + val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val ni = connectivityManager.activeNetworkInfo + + if (ni != null && ni.isConnectedOrConnecting) { + for (listener in onConnectivityChangeListeners) + listener.onConnectivityChange(true) + } else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, java.lang.Boolean.FALSE)) { + for (listener in onConnectivityChangeListeners) + listener.onConnectivityChange(false) + } + } + } + + fun addOnConnectivityChangeListener(listener: OnConnectivityChangeListener) { + onConnectivityChangeListeners.add(listener) + } + + fun removeOnConnectivityChangeListener(listener: OnConnectivityChangeListener) { + onConnectivityChangeListeners.remove(listener) + } + + interface OnConnectivityChangeListener { + fun onConnectivityChange(connected: Boolean) + } +} \ 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 1fa7b24531f948df29521998f3d51067d29018c1..177140d77dbe6c1a5c8a66e159318a03b6cd7ae1 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/NoDbActivity.kt @@ -1,12 +1,60 @@ package ml.adamsprogs.bimba +import android.content.Intent import android.support.v7.app.AppCompatActivity import android.os.Bundle +import android.content.IntentFilter +import android.widget.TextView + -class NoDbActivity : AppCompatActivity() { +class NoDbActivity : AppCompatActivity(), NetworkStateReceiver.OnConnectivityChangeListener, MessageReceiver.OnTimetableDownloadListener { + val networkStateReceiver = NetworkStateReceiver() + val timetableDownloadReceiver = MessageReceiver() + var serviceRunning = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_nodb) + var filter: IntentFilter + filter = IntentFilter("ml.adamsprogs.bimba.timetableDownloaded") + filter.addCategory(Intent.CATEGORY_DEFAULT) + registerReceiver(timetableDownloadReceiver, filter) + timetableDownloadReceiver.addOnTimetableDownloadListener(this) + + if (!isNetworkAvailable(this)) { + (findViewById(R.id.noDbCaption) as TextView).text = getString(R.string.no_db_connect) + filter = IntentFilter("android.net.conn.CONNECTIVITY_CHANGE") + registerReceiver(networkStateReceiver, filter) + networkStateReceiver.addOnConnectivityChangeListener(this) + } else + downloadTimetable() + } + + fun downloadTimetable() { + (findViewById(R.id.noDbCaption) as TextView).text = getString(R.string.no_db_downloading) + serviceRunning = true + intent = Intent(this, TimetableDownloader::class.java) + intent.putExtra("force", true) + startService(intent) + } + + override fun onConnectivityChange(connected: Boolean) { + if (connected && !serviceRunning) + downloadTimetable() + /*if (!connected) + serviceRunning = false*/ + } + + override fun onTimetableDownload() { + timetableDownloadReceiver.removeOnTimetableDownloadListener(this) + networkStateReceiver.removeOnConnectivityChangeListener(this) + startActivity(Intent(this, MainActivity::class.java)) + finish() + } + + override fun onPause() { + super.onPause() + unregisterReceiver(timetableDownloadReceiver) + unregisterReceiver(networkStateReceiver) } } diff --git a/app/src/main/java/ml/adamsprogs/bimba/SplashActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/SplashActivity.kt index 168ec598511fdd5f348ca221fd61338d388dfe61..19f61cc3f8a4243ae8923ddc580b6b1085c5e2b0 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/SplashActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/SplashActivity.kt @@ -3,15 +3,17 @@ import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.content.Intent +import ml.adamsprogs.bimba.models.Timetable class SplashActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - //todo if no db - //startActivity(Intent(this, NoDbActivity::class.java)) - startActivity(Intent(this, MainActivity::class.java)) + if(Timetable(this).isDatabaseHealthy()) + startActivity(Intent(this, MainActivity::class.java)) + else + startActivity(Intent(this, NoDbActivity::class.java)) finish() } } diff --git a/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt b/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt index e06ca9c86d60fa702b7bebd9514f4610b880295a..a39ebacecf238e3ff98cc59a3f0acfb6fb2ce697 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt @@ -3,20 +3,27 @@ import android.app.IntentService import android.content.Context import android.content.Intent +import android.support.v4.app.NotificationCompat import java.net.HttpURLConnection import java.net.URL import org.tukaani.xz.XZInputStream import java.io.* import java.security.MessageDigest import kotlin.experimental.and -import android.net.ConnectivityManager import android.util.Log +import android.app.NotificationManager + class TimetableDownloader : IntentService("TimetableDownloader") { + lateinit var notificationManager: NotificationManager + var size: Int = 0 + override fun onHandleIntent(intent: Intent?) { + if (intent != null) { + notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val prefs = this.getSharedPreferences("ml.adamsprogs.bimba.prefs", Context.MODE_PRIVATE)!! - if (!isNetworkAvailable()) + if (!isNetworkAvailable(this)) return val metadataUrl = URL("https://adamsprogs.ml/w/_media/programmes/bimba/timetable.db.meta") var httpCon = metadataUrl.openConnection() as HttpURLConnection @@ -26,10 +33,13 @@ Log.i("Downloader", "Got metadata") val reader = BufferedReader(InputStreamReader(httpCon.inputStream)) 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) + if (lastModified <= currentLastModified && !intent.getBooleanExtra("force", false)) return Log.i("Downloader", "timetable is newer ($lastModified > $currentLastModified)") + + notify(0) val xzDbUrl = URL("https://adamsprogs.ml/w/_media/programmes/bimba/timetable.db.xz") httpCon = xzDbUrl.openConnection() as HttpURLConnection @@ -53,15 +63,33 @@ sendBroadcast(broadcastIntent) } else { Log.i("Downloader", "downloaded but is wrong") } + + cancelNotification() } } + private fun notify(progress: Int) { + val builder = NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.ic_download) + .setContentTitle(getString(R.string.timetable_downloading)) + .setContentText("$progress KiB/$size KiB") + .setCategory(NotificationCompat.CATEGORY_PROGRESS) + .setOngoing(true) + .setProgress(size, progress, false) + + notificationManager.notify(42, builder.build()) + } + + private fun cancelNotification() { + notificationManager.cancel(42) + } + private fun copyInputStreamToFile(ins: InputStream, file: File, checksum: String): Boolean { val md = MessageDigest.getInstance("SHA-512") var hex = "" try { val out = FileOutputStream(file) - val buf = ByteArray(1024) + val buf = ByteArray(1024) //todo bigger? var lenSum = 0.0f var len = 42 while (len > 0) { @@ -71,6 +99,7 @@ break 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() @@ -85,11 +114,5 @@ } Log.i("Downloader", "checksum is $checksum, and hex is $hex") return checksum == hex } - } - - private fun isNetworkAvailable(): Boolean { - val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager - val activeNetworkInfo = connectivityManager.activeNetworkInfo - return activeNetworkInfo != null && activeNetworkInfo.isConnected } } diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt index 9ef9a47d5def1edfd8576f36eef8f7473cac37ae..9e08ecd35ab476075222b2f4fc731c6e8949fdba 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt @@ -1,14 +1,24 @@ package ml.adamsprogs.bimba.models import android.content.Context +import android.database.Cursor import android.database.sqlite.SQLiteCantOpenDatabaseException import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteDatabaseCorruptException import android.util.Log import java.io.File class Timetable(var context: Context) { var db: SQLiteDatabase? = null + init { + readDbFile() + } + + fun isDatabaseHealthy(): Boolean { + return db != null + } + fun refresh() { readDbFile() } @@ -18,7 +28,10 @@ try { db = SQLiteDatabase.openDatabase(File(context.filesDir, "new_timetable.db").path, null, SQLiteDatabase.OPEN_READONLY) } catch(e: SQLiteCantOpenDatabaseException) { - Log.e("Timetable", "Cannot open db") + Log.e("Timetable", "Cannot open database") + db = null + } catch(e: SQLiteDatabaseCorruptException) { + Log.e("Timetable", "Database is corrupted") db = null } } @@ -26,12 +39,19 @@ fun getStops(): ArrayList<StopSuggestion>? { if (db == null) return null - val cursor = db!!.rawQuery("select name ||char(10)|| headsigns as suggestion, id from stops" + - " join nodes on(stops.symbol = nodes.symbol) order by name, id;", null) val stops = ArrayList<StopSuggestion>() - while (cursor.moveToNext()) - stops.add(StopSuggestion(cursor.getString(0), cursor.getString(1))) - cursor.close() + var cursor : Cursor? = null + try { + cursor = db!!.rawQuery("select name ||char(10)|| headsigns as suggestion, id from stops" + + " join nodes on(stops.symbol = nodes.symbol) order by name, id;", null) + while (cursor.moveToNext()) + stops.add(StopSuggestion(cursor.getString(0), cursor.getString(1))) + }catch (e: SQLiteDatabaseCorruptException) { + cursor?.close() + return null + } finally { + cursor?.close() + } return stops } @@ -42,7 +62,7 @@ val cursor = db!!.rawQuery("select name from nodes join stops on(stops.symbol = nodes.symbol) where id = ?;", listOf(stopId).toTypedArray()) val name: String cursor.moveToNext() - name = cursor.getString(0) + name = cursor.getString(0) cursor.close() return name } @@ -51,9 +71,9 @@ fun getStopDepartures(stopId: String): HashMap>? { if (db == null) return null val cursor = db!!.rawQuery("select lines.number, mode, substr('0'||hour, -2) || ':' || " + - "substr('0'||minute, -2) as time, lowFloor, modification, headsign from departures join "+ - "timetables on(timetable_id = timetables.id) join lines on(line_id = lines.id) where "+ - "stop_id = ? order by mode, time;", listOf(stopId).toTypedArray()) + "substr('0'||minute, -2) as time, lowFloor, modification, headsign from departures join " + + "timetables on(timetable_id = timetables.id) join lines on(line_id = lines.id) where " + + "stop_id = ? order by mode, time;", listOf(stopId).toTypedArray()) val departures = HashMap<String, ArrayList<Departure>>() departures.put("workdays", ArrayList()) departures.put("saturdays", ArrayList()) @@ -66,9 +86,4 @@ } cursor.close() return departures } - - init { - readDbFile() - } - } diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2b16c14e56813b9d6c53f6dee2a9d82729164c0 --- /dev/null +++ b/app/src/main/res/drawable/ic_download.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z" + android:fillColor="#000000"/> +</vector> diff --git a/app/src/main/res/drawable/nodb.xml b/app/src/main/res/drawable/nodb.xml index 4255d8d033055c251983dfa0c42184f1fb987d6d..1fee6a8f9864a21b9ed0400fa435fe5adb58e7d4 100644 --- a/app/src/main/res/drawable/nodb.xml +++ b/app/src/main/res/drawable/nodb.xml @@ -1,67 +1,33 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="285dp" - android:height="508dp" + android:width="1080dp" + android:height="1920dp" android:viewportWidth="285.75" android:viewportHeight="508.0"> <path - android:pathData="M0,0V508H285.75V0Z" + android:pathData="M0,0h285.75v508h-285.75z" android:fillAlpha="1" android:strokeColor="#00000000" - android:fillColor="#f5f5f5" - android:strokeWidth="1.09682584"/> + android:fillColor="#e0e0e0" + android:strokeWidth="2.96499991" + android:strokeAlpha="1"/> <path - android:pathData="M118.39,10.65h11.8v45.79h-11.8z" + android:pathData="M136.13,341.19h13.49v166.81h-13.49z" android:fillAlpha="1" - android:fillType="evenOdd" - android:strokeColor="#00000000" - android:fillColor="#ffffff" - android:strokeWidth="1.09682584"/> - <path - android:pathData="M118.39,95.69h11.8v45.79h-11.8z" - android:fillAlpha="1" - android:fillType="evenOdd" - android:strokeColor="#00000000" - android:fillColor="#ffffff" - android:strokeWidth="1.09682584"/> - <path - android:pathData="M118.39,180.74h11.8v45.79h-11.8z" - android:fillAlpha="1" - android:fillType="evenOdd" - android:strokeColor="#00000000" - android:fillColor="#ffffff" - android:strokeWidth="1.09682584"/> - <path - android:pathData="M118.39,265.78h11.8v45.79h-11.8z" - android:fillAlpha="1" - android:fillType="evenOdd" android:strokeColor="#00000000" - android:fillColor="#ffffff" - android:strokeWidth="1.09682584"/> + android:fillColor="#aaaaaa" + android:strokeWidth="5.5416379" + android:strokeAlpha="1"/> <path - android:pathData="M157.97,342.48l6.86,-9.59l37.36,26.6l-6.86,9.59z" - android:fillType="evenOdd" + android:pathData="M142.88,301.08m-42.33,0a42.33,42.33 69.77,1 1,84.67 0a42.33,42.33 69.77,1 1,-84.67 0" android:strokeColor="#00000000" - android:fillAlpha="1" - android:fillColor="#ffffff" - android:strokeWidth="1.06666672"/> + android:fillColor="#0e518d"/> <path - android:pathData="M227.37,391.87l6.86,-9.59l37.36,26.6l-6.86,9.59z" - android:fillType="evenOdd" + android:pathData="m131.65,282.69 l-10.98,7.52 9.06,6.2L113.25,296.41l0.3,1.93L111.83,304.94l0,8.44l5.23,0l0.45,-2.03l17.69,0l0.45,2.03l14.43,0l0.45,-2.03l17.69,0l0.45,2.03L173.92,313.38L173.92,304.94l-1.73,-6.61 0.31,-1.93L133.57,296.41l9.05,-6.2zM131.65,284.42 L140.09,290.2l0,0.02l-8.44,5.79 -8.44,-5.79l0,-0.02zM114.62,298.33L119.3,298.33L119.3,304.94L112.9,304.94ZM120.52,298.33L128.45,298.33L128.45,304.94L120.52,304.94ZM129.67,298.33l7.93,0l0,6.61l-7.93,0zM138.81,298.33l8.13,0L146.94,304.94L138.81,304.94ZM148.16,298.33l7.93,0l0,6.61l-7.93,0zM157.31,298.33l7.93,0l0,6.61l-7.93,0zM166.45,298.33l4.67,0l1.72,6.61L166.45,304.94ZM119.14,312.66l0,0.69c0,1.51 1.22,2.74 2.74,2.74 1.21,0 2.25,-0.79 2.6,-1.89l3.82,0c0.36,1.1 1.39,1.89 2.6,1.89 1.51,0 2.74,-1.22 2.74,-2.74l-0.01,-0.69L119.14,312.66ZM152.12,312.66 L152.11,313.36c0,1.51 1.22,2.74 2.74,2.74 1.21,0 2.25,-0.79 2.6,-1.89l3.82,0c0.36,1.1 1.39,1.89 2.6,1.89 1.51,0 2.74,-1.22 2.74,-2.74l0,-0.69l-14.49,0z" android:strokeColor="#00000000" - android:fillAlpha="1" - android:fillColor="#ffffff" - android:strokeWidth="1.06666672"/> + android:fillColor="#ffffff"/> <path - android:pathData="m242.98,155.61v32.85h27.21v-33.83h4.92L271.5,22.16L156.09,22.16l-3.61,132.47h4.92v33.83h27.21v-32.85zM260.68,35.24 L262.65,85.61h-99.01l1.97,-50.37z" - android:fillAlpha="1" - android:fillType="evenOdd" - android:strokeColor="#00000000" - android:fillColor="#ffffff" - android:strokeWidth="1.09682584"/> - <path - android:pathData="m151.43,218.53h17.63c3.49,0 6.09,0.16 7.81,0.49 1.71,0.33 3.25,1.01 4.6,2.06 1.35,1.04 2.48,2.43 3.38,4.16 0.9,1.73 1.35,3.68 1.35,5.83 -0,2.33 -0.56,4.47 -1.67,6.42 -1.11,1.95 -2.62,3.41 -4.53,4.38 2.69,0.88 4.75,2.39 6.2,4.52 1.44,2.13 2.17,4.63 2.17,7.51 -0,2.27 -0.47,4.47 -1.4,6.61 -0.93,2.14 -2.21,3.85 -3.82,5.13 -1.61,1.28 -3.61,2.07 -5.97,2.36 -1.48,0.18 -5.06,0.29 -10.74,0.34h-15.01zM160.34,226.82v11.52h5.84c3.47,0 5.63,-0.06 6.47,-0.17 1.52,-0.2 2.72,-0.8 3.6,-1.78 0.87,-0.99 1.31,-2.28 1.31,-3.89 -0,-1.54 -0.38,-2.79 -1.13,-3.76 -0.75,-0.96 -1.87,-1.55 -3.35,-1.75 -0.88,-0.11 -3.42,-0.17 -7.61,-0.17zM160.34,246.64v13.32h8.24c3.21,0 5.24,-0.1 6.11,-0.31 1.32,-0.27 2.4,-0.93 3.23,-1.99 0.83,-1.05 1.25,-2.46 1.25,-4.23 -0,-1.5 -0.32,-2.76 -0.96,-3.81 -0.64,-1.04 -1.57,-1.8 -2.78,-2.28 -1.21,-0.48 -3.85,-0.71 -7.9,-0.71zM195.87,218.53h8.91v26.99c0,4.28 0.11,7.06 0.33,8.33 0.38,2.04 1.29,3.68 2.72,4.91 1.43,1.23 3.39,1.85 5.88,1.85 2.53,0 4.43,-0.58 5.72,-1.75 1.28,-1.17 2.06,-2.6 2.32,-4.3 0.26,-1.7 0.39,-4.52 0.39,-8.46v-27.56h8.91v26.17c-0,5.98 -0.24,10.21 -0.72,12.68 -0.48,2.47 -1.37,4.55 -2.66,6.25 -1.29,1.7 -3.02,3.05 -5.19,4.06 -2.17,1.01 -4.99,1.51 -8.48,1.51 -4.21,0 -7.41,-0.55 -9.58,-1.65 -2.18,-1.1 -3.9,-2.53 -5.16,-4.28 -1.26,-1.76 -2.1,-3.6 -2.5,-5.52 -0.58,-2.85 -0.87,-7.07 -0.87,-12.64zM238.2,252.14 L246.86,251.19c0.52,3.29 1.58,5.7 3.17,7.24 1.59,1.54 3.75,2.31 6.45,2.31 2.87,0 5.03,-0.69 6.48,-2.06 1.45,-1.37 2.18,-2.97 2.18,-4.81 0,-1.18 -0.31,-2.18 -0.92,-3.01 -0.61,-0.83 -1.68,-1.55 -3.2,-2.16 -1.04,-0.41 -3.42,-1.13 -7.13,-2.18 -4.77,-1.34 -8.12,-2.98 -10.05,-4.93 -2.71,-2.74 -4.06,-6.08 -4.06,-10.03 0,-2.54 0.64,-4.91 1.91,-7.12 1.27,-2.21 3.11,-3.89 5.51,-5.05 2.4,-1.16 5.29,-1.73 8.68,-1.73 5.54,0 9.7,1.37 12.5,4.11 2.8,2.74 4.27,6.4 4.41,10.98l-8.91,0.44c-0.38,-2.56 -1.2,-4.4 -2.45,-5.52 -1.25,-1.12 -3.13,-1.68 -5.64,-1.68 -2.59,0 -4.61,0.6 -6.08,1.8 -0.94,0.77 -1.41,1.8 -1.41,3.09 -0,1.18 0.44,2.19 1.32,3.02 1.12,1.06 3.85,2.18 8.18,3.33 4.33,1.16 7.54,2.35 9.61,3.59 2.08,1.23 3.7,2.92 4.87,5.06 1.17,2.14 1.76,4.79 1.76,7.94 -0,2.85 -0.7,5.53 -2.11,8.02 -1.4,2.49 -3.39,4.34 -5.96,5.56 -2.57,1.21 -5.77,1.82 -9.6,1.82 -5.58,0 -9.86,-1.46 -12.85,-4.37 -2.99,-2.91 -4.77,-7.15 -5.36,-12.73z" - android:fillAlpha="1" - android:strokeColor="#00000000" - android:fillColor="#ffffff" - android:strokeWidth="1.09682584"/> + android:pathData="M142.88,301.08m-40.06,0a40.06,40.06 59.4,1 1,80.12 0a40.06,40.06 82.72,1 1,-80.12 0" + android:strokeColor="#f7fbf5" + android:fillColor="#00000000" + android:strokeWidth="6.73600006"/> </vector> diff --git a/app/src/main/res/layout/activity_nodb.xml b/app/src/main/res/layout/activity_nodb.xml index f0993ec7fbeada126ebe5beb61b07c5c98369970..287aaa941d98a4342927ca898de4e9840ee48e38 100644 --- a/app/src/main/res/layout/activity_nodb.xml +++ b/app/src/main/res/layout/activity_nodb.xml @@ -1,14 +1,37 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@drawable/nodb"> +<FrameLayout 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:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@string/no_database_background" + android:scaleType="centerCrop" + app:srcCompat="@drawable/nodb" /> - <android.support.v7.widget.Toolbar - android:id="@+id/toolbar2" + <android.support.constraint.ConstraintLayout android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="?attr/colorPrimary" - android:minHeight="?attr/actionBarSize" - android:theme="?attr/actionBarTheme" /> -</LinearLayout> \ No newline at end of file + android:layout_height="match_parent" + android:orientation="vertical"> + + <TextView + android:id="@+id/noDbCaption" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:layout_marginEnd="8dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:text="" + android:textAlignment="center" + android:textAppearance="@style/TextAppearance.AppCompat.Headline" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.4" /> + </android.support.constraint.ConstraintLayout> +</FrameLayout> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb01817c79fd103271ac9c942e44522b7e89ef1d..a56f3fca135b861588ef4cdbc093a4017ccc9e19 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,4 +11,8 @@ 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_db_connect">Connect to the Internet to download the timetable</string> + <string name="no_db_downloading">Timetable is being downloaded</string> + <string name="timetable_downloading">Downloading timetable</string> </resources>