Some small refactoring for the app (#38)

* Add Gradle versions plugin for simple dependency updates
* Update dependency versions
* Refactor MainActivity to be more Kotlin-like
* Simplify LogActivity a little
* Remove useless run calls in GameDialog
This commit is contained in:
Max K 2020-03-08 13:28:18 +01:00 committed by ◱ PixelyIon
parent 4af37c4367
commit 38f63eced3
6 changed files with 98 additions and 117 deletions

View File

@ -4,7 +4,7 @@ apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion '29.0.2' buildToolsVersion '29.0.3'
defaultConfig { defaultConfig {
applicationId "skyline.emu" applicationId "skyline.emu"
minSdkVersion 26 minSdkVersion 26
@ -47,6 +47,7 @@ android {
sourceCompatibility = 1.8 sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8
} }
ndkVersion '21.0.6113669'
} }
dependencies { dependencies {
@ -54,9 +55,9 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.preference:preference:1.1.0'
implementation 'com.google.android.material:material:1.2.0-alpha02' implementation 'com.google.android.material:material:1.2.0-alpha05'
implementation 'me.xdrop:fuzzywuzzy:1.2.0' implementation 'me.xdrop:fuzzywuzzy:1.2.0'
implementation "androidx.core:core-ktx:1.1.0" implementation "androidx.core:core-ktx:1.2.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'androidx.documentfile:documentfile:1.0.1'
} }

View File

@ -26,32 +26,23 @@ class LogActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.log_activity) setContentView(R.layout.log_activity)
setSupportActionBar(findViewById(R.id.toolbar)) setSupportActionBar(findViewById(R.id.toolbar))
val actionBar = supportActionBar supportActionBar?.setDisplayHomeAsUpEnabled(true)
actionBar?.setDisplayHomeAsUpEnabled(true)
val prefs = PreferenceManager.getDefaultSharedPreferences(this) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val logList = findViewById<ListView>(R.id.log_list) val logList = findViewById<ListView>(R.id.log_list)
adapter = LogAdapter(this, prefs.getBoolean("log_compact", false), prefs.getString("log_level", "3")!!.toInt(), resources.getStringArray(R.array.log_level)) adapter = LogAdapter(this, prefs.getBoolean("log_compact", false), prefs.getString("log_level", "3")!!.toInt(), resources.getStringArray(R.array.log_level))
logList.adapter = adapter logList.adapter = adapter
try { try {
logFile = File(applicationInfo.dataDir + "/skyline.log") logFile = File("${applicationInfo.dataDir}/skyline.log")
val inputStream: InputStream = FileInputStream(logFile) logFile.forEachLine {
val reader = BufferedReader(InputStreamReader(inputStream)) adapter.add(it)
try {
var done = false
while (!done) {
val line = reader.readLine()
if (!(line == null).also { done = it }) {
adapter.add(line)
}
}
} catch (e: IOException) {
Log.w("Logger", "IO Error during access of log file: " + e.message)
Toast.makeText(applicationContext, getString(R.string.io_error) + ": " + e.message, Toast.LENGTH_LONG).show()
} }
} catch (e: FileNotFoundException) { } catch (e: FileNotFoundException) {
Log.w("Logger", "IO Error during access of log file: " + e.message) Log.w("Logger", "IO Error during access of log file: " + e.message)
Toast.makeText(applicationContext, getString(R.string.file_missing), Toast.LENGTH_LONG).show() Toast.makeText(applicationContext, getString(R.string.file_missing), Toast.LENGTH_LONG).show()
finish() finish()
} catch (e: IOException) {
Log.w("Logger", "IO Error during access of log file: " + e.message)
Toast.makeText(applicationContext, getString(R.string.io_error) + ": " + e.message, Toast.LENGTH_LONG).show()
} }
} }
@ -78,8 +69,7 @@ class LogActivity : AppCompatActivity() {
return when (item.itemId) { return when (item.itemId) {
R.id.action_clear -> { R.id.action_clear -> {
try { try {
val fileWriter = FileWriter(logFile, false) logFile.writeText("")
fileWriter.close()
} catch (e: IOException) { } catch (e: IOException) {
Log.w("Logger", "IO Error while clearing the log file: " + e.message) Log.w("Logger", "IO Error while clearing the log file: " + e.message)
Toast.makeText(applicationContext, getString(R.string.io_error) + ": " + e.message, Toast.LENGTH_LONG).show() Toast.makeText(applicationContext, getString(R.string.io_error) + ": " + e.message, Toast.LENGTH_LONG).show()
@ -89,6 +79,14 @@ class LogActivity : AppCompatActivity() {
true true
} }
R.id.action_share_log -> { R.id.action_share_log -> {
uploadAndShareLog()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun uploadAndShareLog() {
val shareThread = Thread(Runnable { val shareThread = Thread(Runnable {
var urlConnection: HttpsURLConnection? = null var urlConnection: HttpsURLConnection? = null
try { try {
@ -98,26 +96,17 @@ class LogActivity : AppCompatActivity() {
urlConnection.setRequestProperty("Host", "hastebin.com") urlConnection.setRequestProperty("Host", "hastebin.com")
urlConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8") urlConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8")
urlConnection.setRequestProperty("Referer", "https://hastebin.com/") urlConnection.setRequestProperty("Referer", "https://hastebin.com/")
urlConnection.setRequestProperty("Connection", "keep-alive") val bufferedWriter = urlConnection.outputStream.bufferedWriter()
val outputStream: OutputStream = BufferedOutputStream(urlConnection.outputStream) bufferedWriter.write(logFile.readText())
val bufferedWriter = BufferedWriter(OutputStreamWriter(outputStream, StandardCharsets.UTF_8))
val fileReader = FileReader(logFile)
var chr: Int
while (fileReader.read().also { chr = it } != -1) {
bufferedWriter.write(chr)
}
bufferedWriter.flush() bufferedWriter.flush()
bufferedWriter.close() bufferedWriter.close()
outputStream.close()
if (urlConnection.responseCode != 200) { if (urlConnection.responseCode != 200) {
Log.e("LogUpload", "HTTPS Status Code: " + urlConnection.responseCode) Log.e("LogUpload", "HTTPS Status Code: " + urlConnection.responseCode)
throw Exception() throw Exception()
} }
val inputStream: InputStream = BufferedInputStream(urlConnection.inputStream) val bufferedReader = urlConnection.inputStream.bufferedReader()
val bufferedReader = BufferedReader(InputStreamReader(inputStream, StandardCharsets.UTF_8)) val key = JSONObject(bufferedReader.readText()).getString("key")
val key = JSONObject(bufferedReader.lines().collect(Collectors.joining())).getString("key")
bufferedReader.close() bufferedReader.close()
inputStream.close()
val result = "https://hastebin.com/$key" val result = "https://hastebin.com/$key"
val sharingIntent = Intent(Intent.ACTION_SEND).setType("text/plain").putExtra(Intent.EXTRA_TEXT, result) val sharingIntent = Intent(Intent.ACTION_SEND).setType("text/plain").putExtra(Intent.EXTRA_TEXT, result)
startActivity(Intent.createChooser(sharingIntent, "Share log url with:")) startActivity(Intent.createChooser(sharingIntent, "Share log url with:"))
@ -125,7 +114,6 @@ class LogActivity : AppCompatActivity() {
runOnUiThread { Toast.makeText(applicationContext, getString(R.string.share_error), Toast.LENGTH_LONG).show() } runOnUiThread { Toast.makeText(applicationContext, getString(R.string.share_error), Toast.LENGTH_LONG).show() }
e.printStackTrace() e.printStackTrace()
} finally { } finally {
assert(urlConnection != null)
urlConnection!!.disconnect() urlConnection!!.disconnect()
} }
}) })
@ -136,9 +124,5 @@ class LogActivity : AppCompatActivity() {
Toast.makeText(applicationContext, getString(R.string.share_error), Toast.LENGTH_LONG).show() Toast.makeText(applicationContext, getString(R.string.share_error), Toast.LENGTH_LONG).show()
e.printStackTrace() e.printStackTrace()
} }
super.onOptionsItemSelected(item)
}
else -> super.onOptionsItemSelected(item)
}
} }
} }

View File

@ -27,53 +27,49 @@ import java.io.File
import java.io.IOException import java.io.IOException
import kotlin.concurrent.thread import kotlin.concurrent.thread
class MainActivity : AppCompatActivity(), View.OnClickListener { class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
private var adapter = GameAdapter(this) private var adapter = GameAdapter(this)
fun notifyUser(text: String) { private fun notifyUser(text: String) {
Snackbar.make(findViewById(android.R.id.content), text, Snackbar.LENGTH_SHORT).show() Snackbar.make(findViewById(android.R.id.content), text, Snackbar.LENGTH_SHORT).show()
} }
private fun findFile(ext: String, loader: BaseLoader, directory: DocumentFile, entries: Int = 0): Int { private fun findFile(ext: String, loader: BaseLoader, directory: DocumentFile, entries: Int = 0): Int {
var mEntries = entries var entryCount = entries
for (file in directory.listFiles()) {
directory.listFiles()
.forEach { file ->
if (file.isDirectory) { if (file.isDirectory) {
mEntries = findFile(ext, loader, file, mEntries) entryCount = findFile(ext, loader, file, entries)
} else { } else {
try { if (ext.equals(file.name?.substringAfterLast("."), ignoreCase = true)) {
if (file.name != null) {
if (ext.equals(file.name?.substring((file.name!!.lastIndexOf(".")) + 1), ignoreCase = true)) {
val document = RandomAccessDocument(this, file) val document = RandomAccessDocument(this, file)
if (loader.verifyFile(document)) { if (loader.verifyFile(document)) {
val entry = loader.getTitleEntry(document, file.uri) val entry = loader.getTitleEntry(document, file.uri)
val header = (mEntries == 0) val header = (entryCount == 0)
runOnUiThread { runOnUiThread {
if(header) if (header)
adapter.addHeader(getString(R.string.nro)) adapter.addHeader(getString(R.string.nro))
adapter.addItem(GameItem(entry)) adapter.addItem(GameItem(entry))
} }
mEntries++ entryCount++
} }
document.close() document.close()
} }
} }
} catch (e: StringIndexOutOfBoundsException) {
Log.w("findFile", e.message!!)
} }
}
} return entryCount
return mEntries
} }
private fun refreshFiles(tryLoad: Boolean) { private fun refreshFiles(tryLoad: Boolean) {
if (tryLoad) { if (tryLoad) {
try { try {
adapter.load(File(applicationInfo.dataDir + "/roms.bin")) adapter.load(File("${applicationInfo.dataDir}/roms.bin"))
return return
} catch (e: Exception) { } catch (e: Exception) {
Log.w("refreshFiles", "Ran into exception while loading: " + e.message) Log.w("refreshFiles", "Ran into exception while loading: ${e.message}")
} }
} }
thread(start = true) { thread(start = true) {
@ -86,9 +82,9 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
if (entries == 0) if (entries == 0)
adapter.addHeader(getString(R.string.no_rom)) adapter.addHeader(getString(R.string.no_rom))
try { try {
adapter.save(File(applicationInfo.dataDir + "/roms.bin")) adapter.save(File("${applicationInfo.dataDir}/roms.bin"))
} catch (e: IOException) { } catch (e: IOException) {
Log.w("refreshFiles", "Ran into exception while saving: " + e.message) Log.w("refreshFiles", "Ran into exception while saving: ${e.message}")
} }
} }
sharedPreferences.edit().putBoolean("refresh_required", false).apply() sharedPreferences.edit().putBoolean("refresh_required", false).apply()

View File

@ -35,7 +35,6 @@ class GameDialog() : DialogFragment() {
val shortcutManager = activity?.getSystemService(ShortcutManager::class.java)!! val shortcutManager = activity?.getSystemService(ShortcutManager::class.java)!!
game_pin.isEnabled = shortcutManager.isRequestPinShortcutSupported game_pin.isEnabled = shortcutManager.isRequestPinShortcutSupported
game_pin.setOnClickListener { game_pin.setOnClickListener {
run {
val info = ShortcutInfo.Builder(context, item?.title) val info = ShortcutInfo.Builder(context, item?.title)
info.setShortLabel(item?.meta?.name!!) info.setShortLabel(item?.meta?.name!!)
info.setActivity(ComponentName(context!!, GameActivity::class.java)) info.setActivity(ComponentName(context!!, GameActivity::class.java))
@ -46,14 +45,11 @@ class GameDialog() : DialogFragment() {
info.setIntent(intent) info.setIntent(intent)
shortcutManager.requestPinShortcut(info.build(), null) shortcutManager.requestPinShortcut(info.build(), null)
} }
}
game_play.setOnClickListener { game_play.setOnClickListener {
run {
val intent = Intent(activity, GameActivity::class.java) val intent = Intent(activity, GameActivity::class.java)
intent.data = item?.uri intent.data = item?.uri
startActivity(intent) startActivity(intent)
} }
}
} else } else
activity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit() activity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit()
} }

View File

@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.60' ext.kotlin_version = '1.3.61'
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.3' classpath 'com.android.tools.build:gradle:3.6.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
@ -16,6 +16,10 @@ buildscript {
} }
} }
plugins {
id "com.github.ben-manes.versions" version "0.28.0"
}
allprojects { allprojects {
repositories { repositories {
google() google()

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.1-all.zip