diff --git a/.travis.yml b/.travis.yml index 50a993d..d55d4eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,10 +10,10 @@ android: - platform-tools # The BuildTools version used by your project - - build-tools-25.0.3 + - build-tools-28.0.2 # The SDK version used to compile your project - - android-25 + - android-28 before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock cache: diff --git a/app/build.gradle b/app/build.gradle index 4707fa5..170a9e0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,13 +4,13 @@ apply plugin: 'kotlin-kapt' apply plugin: 'jacoco' android { - compileSdkVersion 25 - buildToolsVersion "25.0.3" + compileSdkVersion 28 + buildToolsVersion "28.0.2" defaultConfig { applicationId "io.github.hidroh.tldroid" - minSdkVersion 9 - targetSdkVersion 25 + minSdkVersion 14 + targetSdkVersion 28 versionCode 10 versionName "1.6" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -76,7 +76,6 @@ dependencies { 'com.squareup.moshi:moshi:1.2.0', 'com.squareup.okio:okio:1.8.0', "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" - kapt "com.android.databinding:compiler:2.3.2" testImplementation 'junit:junit:4.12', 'org.mockito:mockito-core:1.10.19', 'org.powermock:powermock-module-junit4:1.6.2', diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/Application.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/Application.kt index ccc2358..22db6e0 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/Application.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/Application.kt @@ -6,6 +6,7 @@ import android.graphics.Typeface class Application : android.app.Application() { companion object { var MONOSPACE_TYPEFACE: Typeface? = null + private set } override fun onCreate() { diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/Bindings.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/Bindings.kt index 9b7fc91..e2f468c 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/Bindings.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/Bindings.kt @@ -5,7 +5,7 @@ import android.database.Cursor import android.databinding.BaseObservable import android.databinding.BindingAdapter import android.support.annotation.AttrRes -import android.support.annotation.IdRes +import android.support.annotation.ColorInt import android.support.v4.content.ContextCompat import android.text.SpannableString import android.text.Spanned @@ -15,7 +15,7 @@ import android.webkit.WebView import android.widget.TextView object Bindings { - private val FORMAT_HTML_COLOR = "%06X" + private const val FORMAT_HTML_COLOR = "%06X" @JvmStatic @BindingAdapter("bind:monospace") @@ -35,8 +35,8 @@ object Bindings { val spannable = SpannableString(textView.text) val start = TextUtils.indexOf(spannable, highlightText) if (start >= 0) { - spannable.setSpan(ForegroundColorSpan(ContextCompat.getColor( - textView.context, getIdRes(textView.context, highlightColor))), + spannable.setSpan(ForegroundColorSpan(getColorFromAttr( + textView.context, highlightColor)), start, start + highlightText.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE) } @@ -60,8 +60,7 @@ object Bindings { if (TextUtils.isEmpty(html)) { return } - webView.setBackgroundColor(ContextCompat.getColor(webView.context, - getIdRes(webView.context, backgroundColor))) + webView.setBackgroundColor(getColorFromAttr(webView.context, backgroundColor)) webView.loadDataWithBaseURL(null, wrapHtml(webView.context, html, textColor, linkColor, textSize, margin), "text/html", "UTF-8", null) @@ -83,20 +82,19 @@ object Bindings { } private fun toHtmlColor(context: Context, @AttrRes colorAttr: Int): String { - return String.format(FORMAT_HTML_COLOR, 0xFFFFFF and ContextCompat.getColor(context, - getIdRes(context, colorAttr))) + return String.format(FORMAT_HTML_COLOR, 0xFFFFFF and getColorFromAttr(context, colorAttr)) } private fun toHtmlPx(context: Context, dimen: Float): Float { return dimen / context.resources.displayMetrics.density } - @IdRes - private fun getIdRes(context: Context, @AttrRes attrRes: Int): Int { + @ColorInt + private fun getColorFromAttr(context: Context, @AttrRes attrRes: Int): Int { val ta = context.theme.obtainStyledAttributes(intArrayOf(attrRes)) val resId = ta.getResourceId(0, 0) ta.recycle() - return resId + return ContextCompat.getColor(context, resId) } class Command : BaseObservable() { diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/CommandActivity.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/CommandActivity.kt index 35367ba..5e7f393 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/CommandActivity.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/CommandActivity.kt @@ -5,19 +5,21 @@ import android.databinding.DataBindingUtil import android.databinding.ViewDataBinding import android.net.Uri import android.os.AsyncTask +import android.os.Build import android.os.Bundle import android.preference.PreferenceManager +import android.support.annotation.RequiresApi import android.support.design.widget.CollapsingToolbarLayout +import android.support.v4.text.HtmlCompat import android.support.v4.view.MenuItemCompat import android.support.v7.app.ActionBar import android.support.v7.widget.ShareActionProvider -import android.support.v7.widget.Toolbar -import android.text.Html import android.text.TextUtils import android.view.Menu import android.view.MenuItem import android.view.View import android.webkit.WebChromeClient +import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient import java.lang.ref.WeakReference @@ -26,8 +28,8 @@ class CommandActivity : ThemedActivity() { companion object { val EXTRA_QUERY = CommandActivity::class.java.name + ".EXTRA_QUERY" val EXTRA_PLATFORM = CommandActivity::class.java.name + ".EXTRA_PLATFORM" - private val STATE_CONTENT = "state:content" - private val PLATFORM_OSX = "osx" + private const val STATE_CONTENT = "state:content" + private const val PLATFORM_OSX = "osx" } private var mContent: String? = null @@ -40,21 +42,27 @@ class CommandActivity : ThemedActivity() { mQuery = intent.getStringExtra(EXTRA_QUERY) mPlatform = intent.getStringExtra(EXTRA_PLATFORM) title = mQuery - mBinding = DataBindingUtil.setContentView(this, R.layout.activity_command) - setSupportActionBar(findViewById(R.id.toolbar) as Toolbar?) + mBinding = DataBindingUtil.setContentView(this, R.layout.activity_command) + setSupportActionBar(findViewById(R.id.toolbar)) supportActionBar!!.displayOptions = ActionBar.DISPLAY_SHOW_HOME or ActionBar.DISPLAY_HOME_AS_UP or ActionBar.DISPLAY_SHOW_TITLE - val collapsingToolbar = findViewById(R.id.collapsing_toolbar_layout) as CollapsingToolbarLayout? + val collapsingToolbar = findViewById(R.id.collapsing_toolbar_layout) collapsingToolbar!!.setExpandedTitleTypeface(Application.MONOSPACE_TYPEFACE) collapsingToolbar.setCollapsedTitleTypeface(Application.MONOSPACE_TYPEFACE) - val webView = findViewById(R.id.web_view) as WebView? - webView!!.setWebChromeClient(WebChromeClient()) - webView.setWebViewClient(object : WebViewClient() { + val webView = findViewById(R.id.web_view) + webView!!.webChromeClient = WebChromeClient() + webView.webViewClient = object : WebViewClient() { + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { + startActivity(Intent(Intent.ACTION_VIEW, request.url)) + return true + } + override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) return true } - }) + } if (savedInstanceState != null) { mContent = savedInstanceState.getString(STATE_CONTENT) } @@ -87,7 +95,7 @@ class CommandActivity : ThemedActivity() { .setShareIntent(Intent(Intent.ACTION_SEND) .setType("text/plain") .putExtra(Intent.EXTRA_SUBJECT, mQuery) - .putExtra(Intent.EXTRA_TEXT, Html.fromHtml(mContent).toString())) + .putExtra(Intent.EXTRA_TEXT, HtmlCompat.fromHtml(mContent!!, HtmlCompat.FROM_HTML_MODE_LEGACY).toString())) } menu.findItem(R.id.menu_run).isVisible = visible && !TextUtils.equals(PLATFORM_OSX, mPlatform) return super.onPrepareOptionsMenu(menu) @@ -113,7 +121,7 @@ class CommandActivity : ThemedActivity() { internal fun render(html: String?) { mContent = html ?: "" - supportInvalidateOptionsMenu() + invalidateOptionsMenu() // just display a generic message if empty for now mBinding!!.setVariable(io.github.hidroh.tldroid.BR.content, if (TextUtils.isEmpty(mContent)) getString(R.string.empty_html) else html) diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/MainActivity.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/MainActivity.kt index 21eaaf6..2f65267 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/MainActivity.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/MainActivity.kt @@ -31,10 +31,10 @@ class MainActivity : ThemedActivity() { private fun setContentView() { DataBindingUtil.setContentView(this, R.layout.activity_main) - findViewById(R.id.info_button)!!.setOnClickListener { showInfo() } - findViewById(R.id.list_button)!!.setOnClickListener { showList() } - findViewById(R.id.settings_button)!!.setOnClickListener { showThemeOptions() } - mEditText = findViewById(R.id.edit_text) as AutoCompleteTextView? + findViewById(R.id.info_button)!!.setOnClickListener { showInfo() } + findViewById(R.id.list_button)!!.setOnClickListener { showList() } + findViewById(R.id.settings_button)!!.setOnClickListener { showThemeOptions() } + mEditText = findViewById(R.id.edit_text) mEditText!!.setOnEditorActionListener { v, actionId, _ -> actionId == EditorInfo.IME_ACTION_SEARCH && search(v.text.toString(), null) } @@ -120,7 +120,7 @@ class MainActivity : ThemedActivity() { } private class CursorAdapter(context: Context) : - ResourceCursorAdapter(context, R.layout.dropdown_item, null, false) { + ResourceCursorAdapter(context, R.layout.dropdown_item, null, ResourceCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER) { private val mInflater: LayoutInflater = LayoutInflater.from(context) private var mQueryString: String? = null diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/NetworkConnection.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/NetworkConnection.kt index efd8028..07a3619 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/NetworkConnection.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/NetworkConnection.kt @@ -23,8 +23,7 @@ class NetworkConnection(url: String) { } fun getInputStream(): InputStream? { - inputStream = try { connection?.inputStream ?: null } catch (e: IOException) { null } - return inputStream + return try { connection?.inputStream } catch (e: IOException) { null } } fun setIfModifiedSince(ifModifiedSince: Long) { diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/RunActivity.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/RunActivity.kt index 437788e..a2b8778 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/RunActivity.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/RunActivity.kt @@ -16,8 +16,8 @@ import java.lang.ref.WeakReference class RunActivity : ThemedActivity() { companion object { val EXTRA_COMMAND = RunActivity::class.java.name + ".EXTRA_COMMAND" - private val STATE_ERROR = "state:error" - private val STATE_OUTPUT = "state:output" + private const val STATE_ERROR = "state:error" + private const val STATE_OUTPUT = "state:output" } private var mOutput: TextView? = null @@ -29,11 +29,11 @@ class RunActivity : ThemedActivity() { val snackbar = Snackbar.make(findViewById(android.R.id.content), R.string.run_warning, Snackbar.LENGTH_INDEFINITE) snackbar.setAction(android.R.string.ok, { snackbar.dismiss() }).show() - mOutput = findViewById(R.id.output) as TextView? - mError = findViewById(R.id.error) as TextView? + mOutput = findViewById(R.id.output) + mError = findViewById(R.id.error) val command = intent.getStringExtra(EXTRA_COMMAND) - (findViewById(R.id.prompt) as TextView).append(command) - (findViewById(R.id.edit_text) as EditText).setOnEditorActionListener { v, _, _ -> + (findViewById(R.id.prompt)).append(command) + (findViewById(R.id.edit_text)).setOnEditorActionListener { v, _, _ -> execute(command, v.text.toString().trim()) true } @@ -71,21 +71,17 @@ class RunActivity : ThemedActivity() { internal class RunTask(runActivity: RunActivity) : AsyncTask>() { - private val mRunActivity: WeakReference - - init { - mRunActivity = WeakReference(runActivity) - } + private val mRunActivity = WeakReference(runActivity) override fun doInBackground(vararg params: String): Pair { - try { - val process = Runtime.getRuntime().exec(params) - val stderr = Utils.readUtf8(process.errorStream) - val stdout = Utils.readUtf8(process.inputStream) - process.destroy() - return Pair.create(stdout, stderr) + return try { + val process = Runtime.getRuntime().exec(params) + val stderr = Utils.readUtf8(process.errorStream) + val stdout = Utils.readUtf8(process.inputStream) + process.destroy() + Pair.create(stdout, stderr) } catch (e: IOException) { - return Pair.create(null, e.message) + Pair.create(null, e.message) } } diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/SyncService.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/SyncService.kt index f1b8bec..e627e5b 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/SyncService.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/SyncService.kt @@ -18,8 +18,9 @@ import java.util.* class SyncService : IntentService(SyncService.TAG) { companion object { private const val TAG = "SyncService" - private const val INDEX_URL = "http://tldr-pages.github.io/assets/index.json" - private const val ZIP_URL = "http://tldr-pages.github.io/assets/tldr.zip" + private const val BASE_URL = "https://tldr.sh/assets" + private const val INDEX_URL = "$BASE_URL/index.json" + private const val ZIP_URL = "$BASE_URL/tldr.zip" const val EXTRA_ASSET_TYPE = "$TAG.EXTRA_ASSET_TYPE" const val PREF_LAST_REFRESHED = INDEX_URL const val PREF_LAST_ZIPPED = ZIP_URL @@ -84,7 +85,7 @@ class SyncService : IntentService(SyncService.TAG) { } private fun persist(commands: Commands?) { - if (commands == null || commands.commands == null || commands.commands!!.size == 0) { + if (commands?.commands == null || commands.commands!!.isEmpty()) { return } PreferenceManager.getDefaultSharedPreferences(context) diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/TldrProvider.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/TldrProvider.kt index fd025aa..e13135c 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/TldrProvider.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/TldrProvider.kt @@ -14,8 +14,8 @@ class TldrProvider : ContentProvider() { companion object { const val AUTHORITY = "io.github.hidroh.tldroid.provider" - val URI_COMMAND = Uri - .parse("content://" + AUTHORITY) + val URI_COMMAND: Uri = Uri + .parse("content://$AUTHORITY") .buildUpon() .appendPath(CommandEntry.TABLE_NAME) .build() @@ -35,7 +35,7 @@ class TldrProvider : ContentProvider() { private var mDbHelper: DbHelper? = null override fun onCreate(): Boolean { - mDbHelper = DbHelper(context) + mDbHelper = DbHelper(context!!) return true } @@ -72,7 +72,10 @@ class TldrProvider : ContentProvider() { values, selection, selectionArgs) else 0 } - class DbHelper : SQLiteOpenHelper { + class DbHelper(context: Context) : SQLiteOpenHelper( + context, TldrProvider.DbHelper.DB_NAME, + null, TldrProvider.DbHelper.DB_VERSION + ) { companion object { private const val DB_NAME = "tldr.db" private const val DB_VERSION = 2 @@ -86,10 +89,7 @@ class TldrProvider : ContentProvider() { private const val SQL_DROP_COMMAND_TABLE = "DROP TABLE IF EXISTS ${CommandEntry.TABLE_NAME}" } - constructor(context: Context) : super(context, TldrProvider.DbHelper.DB_NAME, - null, TldrProvider.DbHelper.DB_VERSION) - - override fun onCreate(db: SQLiteDatabase) { + override fun onCreate(db: SQLiteDatabase) { db.execSQL(SQL_CREATE_COMMAND_TABLE) } diff --git a/app/src/main/kotlin/io/github/hidroh/tldroid/Utils.kt b/app/src/main/kotlin/io/github/hidroh/tldroid/Utils.kt index b973fcd..686ed22 100644 --- a/app/src/main/kotlin/io/github/hidroh/tldroid/Utils.kt +++ b/app/src/main/kotlin/io/github/hidroh/tldroid/Utils.kt @@ -8,10 +8,10 @@ import java.io.IOException import java.io.InputStream internal object Utils { - private val KEY_THEME: String = "pref:theme" - private val VAL_THEME_SOLARIZED: String = "theme:solarized" - private val VAL_THEME_AFTERGLOW: String = "theme:afterglow" - private val VAL_THEME_TOMORROW: String = "theme:tomorrow" + private const val KEY_THEME = "pref:theme" + private const val VAL_THEME_SOLARIZED = "theme:solarized" + private const val VAL_THEME_AFTERGLOW = "theme:afterglow" + private const val VAL_THEME_TOMORROW = "theme:tomorrow" @Throws(IOException::class) fun readUtf8(inputStream: InputStream): String { @@ -33,10 +33,10 @@ internal object Utils { fun loadTheme(context: Context): Int { val theme = PreferenceManager.getDefaultSharedPreferences(context) .getString(KEY_THEME, VAL_THEME_SOLARIZED) - when (theme) { - VAL_THEME_AFTERGLOW -> return R.style.AppTheme_Afterglow - VAL_THEME_TOMORROW -> return R.style.AppTheme_Tomorrow - else -> return R.style.AppTheme + return when (theme) { + VAL_THEME_AFTERGLOW -> R.style.AppTheme_Afterglow + VAL_THEME_TOMORROW -> R.style.AppTheme_Tomorrow + else -> R.style.AppTheme } } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/io/github/hidroh/tldroid/MarkdownProcessorTest.kt b/app/src/test/kotlin/io/github/hidroh/tldroid/MarkdownProcessorTest.kt index 8a73408..95f0a09 100644 --- a/app/src/test/kotlin/io/github/hidroh/tldroid/MarkdownProcessorTest.kt +++ b/app/src/test/kotlin/io/github/hidroh/tldroid/MarkdownProcessorTest.kt @@ -7,9 +7,9 @@ import android.content.Context import android.database.Cursor import android.net.Uri import android.text.TextUtils -import junit.framework.Assert.assertNull import org.assertj.core.api.Assertions.assertThat import org.junit.After +import org.junit.Assert.assertNull import org.junit.Before import org.junit.Test import org.junit.runner.RunWith diff --git a/build.gradle b/build.gradle index 95e6799..3a9fc26 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,14 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlinVersion = '1.1.2-4' - ext.supportLibraryVersion = '25.3.1' + ext.kotlinVersion = '1.2.70' + ext.supportLibraryVersion = '28.0.0-rc02' repositories { jcenter() - maven { url 'https://maven.google.com' } + google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0-alpha3' + classpath 'com.android.tools.build:gradle:3.3.0-alpha11' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" // NOTE: Do not place your application dependencies here; they belong @@ -19,7 +19,7 @@ buildscript { allprojects { repositories { jcenter() - maven { url 'https://maven.google.com' } + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e7c91e9..ef9b31b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sat May 20 11:47:47 IST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-milestone-1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip