some changes

This commit is contained in:
Tucan444 2021-03-22 09:12:29 +01:00
parent c1733e7773
commit 8603a2aa38
25 changed files with 1103 additions and 102 deletions

@ -1,6 +1,7 @@
<component name="ProjectDictionaryState"> <component name="ProjectDictionaryState">
<dictionary name="ben44"> <dictionary name="ben44">
<words> <words>
<w>filetype</w>
<w>initing</w> <w>initing</w>
</words> </words>
</dictionary> </dictionary>

@ -1,7 +1,6 @@
plugins { plugins {
id 'com.android.application' id 'com.android.application'
id 'kotlin-android' id 'kotlin-android'
id 'com.chaquo.python'
id 'kotlin-android-extensions' id 'kotlin-android-extensions'
} }
@ -11,7 +10,7 @@ android {
defaultConfig { defaultConfig {
applicationId "com.example.wikispot" applicationId "com.example.wikispot"
minSdkVersion 16 minSdkVersion 23
targetSdkVersion 30 targetSdkVersion 30
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
@ -19,23 +18,6 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
sourceSets {
main {
python {
srcDirs = ["src/main/python"]
}
}
}
python {
pip {
install "requests"
}
}
ndk {
abiFilters "armeabi-v7a", "x86"
}
} }
buildFeatures { buildFeatures {
@ -67,6 +49,7 @@ dependencies {
implementation 'androidx.navigation:navigation-ui-ktx:2.3.4' implementation 'androidx.navigation:navigation-ui-ktx:2.3.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.preference:preference:1.1.1'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

@ -1,19 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.wikispot"> package="com.example.wikispot">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application <application
android:allowBackup="true" android:allowBackup="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/Theme.WikiSpotWithActionBar"> android:theme="@style/Theme.WikiSpotWithActionBar">
<activity android:name=".activities.MainActivity" <activity android:name=".activities.MainActivity">
android:launchMode="singleTask">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

@ -1,19 +1,13 @@
package com.example.wikispot.activities package com.example.wikispot.activities
import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.chaquo.python.Python import com.example.wikispot.*
import com.chaquo.python.android.AndroidPlatform import com.example.wikispot.modelClasses.SettingsSaveManager
import com.example.wikispot.R
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import org.json.JSONArray
import org.json.JSONObject
import java.util.*
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@ -27,12 +21,39 @@ class MainActivity : AppCompatActivity() {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
/*if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
ManifestRelatedVariables.REQUEST_READ_EXTERNAL)
} */
loadSettings()
ServerManagement.serverManager.addActivityConnection(this, "main",0)
ServerManagement.serverManager.getData(this, this, 0, "", "", true)
setTheme(getThemeId())
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
val navController = findNavController(R.id.mainFragmentHost) val navController = findNavController(R.id.mainFragmentHost)
mainBottomNavigationView.setupWithNavController(navController) mainBottomNavigationView.setupWithNavController(navController)
handleExtras()
println("[debug] ${getDataFromServer()}")
}
private fun handleExtras() {
when (intent.getStringExtra(IntentsKeys.startFragment)) {
"chatFragment" -> {mainBottomNavigationView.selectedItemId = R.id.chatFragment}
"exploreFragment" -> {mainBottomNavigationView.selectedItemId = R.id.exploreFragment}
// skipping home fragment because were already here
"mapFragment" -> {mainBottomNavigationView.selectedItemId = R.id.mapFragment}
"settingsFragment" -> {mainBottomNavigationView.selectedItemId = R.id.settingsFragment}
}
}
private fun loadSettings() {
val settingsSaveManager = SettingsSaveManager(this)
settingsSaveManager.loadSettings()
} }
} }

@ -0,0 +1,18 @@
package com.example.wikispot
import android.app.Activity
import android.os.Build
import androidx.annotation.RequiresApi
import kotlinx.android.synthetic.main.activity_main.*
// for serverManager
fun Activity.receiveData(data: String) {
when (this.localClassName) {
"activities.MainActivity" -> { this.receiveDataForMainActivity(data) }
}
}
fun Activity.receiveDataForMainActivity(data: String) {
}

@ -1,4 +1,4 @@
package com.example.wikispot.models_and_adapters package com.example.wikispot.adapters
import android.content.Context import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.wikispot.R import com.example.wikispot.R
import com.example.wikispot.modelsForAdapters.PlacePreview
import kotlinx.android.synthetic.main.explore_list_item.view.* import kotlinx.android.synthetic.main.explore_list_item.view.*

@ -0,0 +1,124 @@
package com.example.wikispot
import android.content.Context
import android.os.Environment
import android.view.View
import android.widget.Toast
import com.google.android.material.snackbar.Snackbar
import okhttp3.*
import org.json.JSONArray
import java.io.*
import java.nio.channels.FileChannel
import java.nio.charset.Charset
// for showing messages
fun Context.showToast(message: String, length: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, length).show()
}
fun Context.showSnack(message: String, view: View, length: Int = Snackbar.LENGTH_LONG) {
Snackbar.make(this, view, message, length).show()
}
// for theme
fun Context.getThemeId(): Int {
if (ThemeOptions.darkTheme) {
if (ThemeOptions.actionBar) {
return R.style.Theme_WikiSpotWithActionBarDark
} else {
return R.style.Theme_WikiSpotDark
}
} else {
if (ThemeOptions.actionBar) {
return R.style.Theme_WikiSpotWithActionBar
} else {
return R.style.Theme_WikiSpot
}
}
}
// for client
fun Context.getDataFromServer(): String {
// requesting data
val url = "http://192.168.1.230:8000/devices_list"
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
var receivedResponse = ""
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
response.body?.let {
receivedResponse = response.body!!.string()
}
}
override fun onFailure(call: Call, e: IOException) {
println("Request Failed")
println(e)
}
})
Thread.sleep(400)
println("[debug] received string: $receivedResponse")
try {
JSONArray(receivedResponse)
return receivedResponse
} catch (exception: Throwable) {
return "[]"
}
}
// working with files
fun Context.createFile(filename: String, filetype: String): File {
val storageDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
if (!storageDir?.exists()!!) {
storageDir.mkdir()
}
return File(storageDir, "$filename.$filetype")
}
fun Context.getFile(filename: String, filetype: String): String {
val file = (getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)?.absolutePath ?: "") + "/$filename.$filetype"
val stream = FileInputStream(file)
var returnString = ""
stream.use { streamInUse ->
val fileChannel = streamInUse.channel
val mappedByteBuffer = fileChannel.map(
FileChannel.MapMode.READ_ONLY,
0,
fileChannel.size()
)
returnString = Charset.defaultCharset().decode(mappedByteBuffer).toString()
}
return returnString
}
fun Context.saveString(accessKey: String, stringValue: String, preferencesFilename: String="generalPreferences") {
val sharedPreferences = getSharedPreferences(preferencesFilename, Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.apply{
putString(accessKey, stringValue)
}.apply()
}
fun Context.getStringFromSharedPreferences(accessKey: String, preferencesFilename: String="generalPreferences"): String {
val sharedPreferences = getSharedPreferences(preferencesFilename, Context.MODE_PRIVATE)
val returnedString = sharedPreferences.getString(accessKey, "")
returnedString?.let {
return returnedString
}
return ""
}

@ -1,39 +0,0 @@
package com.example.wikispot
import android.content.Context
import android.view.View
import android.widget.Toast
import com.chaquo.python.Python
import com.chaquo.python.android.AndroidPlatform
import com.google.android.material.snackbar.Snackbar
import org.json.JSONObject
fun Context.showToast(message: String, length: Int=Toast.LENGTH_SHORT) {
Toast.makeText(this, message, length).show()
}
fun Context.showSnack(message: String, view: View, length: Int = Snackbar.LENGTH_LONG) {
Snackbar.make(this, view, message, length).show()
}
fun Context.getDataFromServer(): MutableList<JSONObject> {
// initing
if (!Python.isStarted()) {
Python.start(AndroidPlatform(this))
}
// getting file
val python = Python.getInstance()
val pythonFile = python.getModule("server_manager")
// getting the data
pythonFile.callAttr("init")
val size = pythonFile.callAttr("get_length").toInt()
val jsonList = mutableListOf<JSONObject>()
for (n in 0 until size) {
jsonList.add(n, JSONObject(pythonFile.callAttr("get_json", n).toString()))
}
return jsonList
}

@ -0,0 +1,71 @@
package com.example.wikispot.fragments
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import com.example.wikispot.R
import com.example.wikispot.ServerManagement
import com.example.wikispot.modelClasses.JsonManager
import kotlinx.android.synthetic.main.fragment_another_debug.*
import org.json.JSONObject
import kotlin.random.Random
class anotherDebugFragment : Fragment(R.layout.fragment_another_debug) {
private lateinit var jsonManager: JsonManager
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
jsonManager = JsonManager(requireContext(), "[]", "JSONArray", true)
generateAndSaveDataBtn.setOnClickListener {
val generatedData = JSONObject()
for (n in 0 until 10) {
generatedData.put("$n", Random.nextInt(0, 100))
}
context?.let {
jsonManager = JsonManager(requireContext(), generatedData.toString(), "JSONObject", true)
jsonManager.saveJson("test")
}
println("[debug] saved generated data")
}
loadAndShowDataBtn.setOnClickListener {
val json = jsonManager.loadJson(requireContext(), "test", "JSONObject")
dataContentView.text = json.currentJsonObject.toString()
}
stopConnectionBtn.setOnClickListener {
ServerManagement.serverManager.deleteConnection("debug", "view")
}
createViewConnectionBtn.setOnClickListener {
val attributePath = attributePathInput.text.toString()
val setWholeContent = wholeContentCheckBox.isChecked
val filePath = filePathInput.text.toString()
ServerManagement.serverManager.deleteConnection("debug", "view")
ServerManagement.serverManager.addViewConnection(requireContext(), dataContentView, "debug",0, filePath, attributePath, setWholeContent)
}
// handling navigation between debug fragments
goFirstDegubFragmentBtn.setOnClickListener {
cleanup()
Navigation.findNavController(it).navigate(R.id.navigateBackToDebugFragment)
}
}
override fun onDestroy() {
super.onDestroy()
cleanup()
}
private fun cleanup() {
ServerManagement.serverManager.deleteConnection("debug")
}
}

@ -4,16 +4,16 @@ import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import com.example.wikispot.R import com.example.wikispot.R
import com.example.wikispot.getDataFromServer import com.example.wikispot.getDataFromServer
import com.example.wikispot.showSnack import com.example.wikispot.modelClasses.JsonManager
import kotlinx.android.synthetic.main.fragment_debug.* import kotlinx.android.synthetic.main.fragment_debug.*
import org.json.JSONObject
class debugFragment : Fragment(R.layout.fragment_debug) { class debugFragment : Fragment(R.layout.fragment_debug) {
private var jsonList: MutableList<JSONObject> = mutableListOf<JSONObject>() private lateinit var jsonManager: JsonManager
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -21,20 +21,37 @@ class debugFragment : Fragment(R.layout.fragment_debug) {
getDataBtn.setOnClickListener { getDataBtn.setOnClickListener {
context?.let { context?.let {
jsonList = requireContext().getDataFromServer() jsonManager = JsonManager(requireContext(), requireContext().getDataFromServer(), "JSONArray", true)
sizeView.text = "Amount of json's: ${jsonList.size}" sizeView.text = jsonManager.getLengthOfJsonArray().toString()
} }
} }
displayJsonFileBtn.setOnClickListener { getJsonFileBtn.setOnClickListener {
val id = idInput.text.toString().toInt() val id = idInput.text.toString().toInt()
if (id >= jsonList.size) { jsonFileContentView.text = jsonManager.getJsonObject(id).toString()
context?.let { }
requireContext().showSnack("Id out of range.", displayJsonFileBtn)
} getAttributeContentBtn.setOnClickListener {
val attributeName = attributeNameInput.text.toString()
if ("/" in attributeName) {
attributeContentView.text = jsonManager.getAttributeContentByPath(attributeNameInput.text.toString())
} else { } else {
jsonFileOutputView.text = jsonList[id].toString() attributeContentView.text = jsonManager.getAttributeContent(attributeNameInput.text.toString())
} }
} }
clearAttributeBtn.setOnClickListener {
jsonManager.clearSelectedAttribute()
attributeContentView.text = "attribute content"
}
attributeNameInput.setOnClickListener {
attributeContentView.text = jsonManager.getCurrentJsonAttributeContent()
}
// handling navigation between debug fragments
goSecondDebugFragmentBtn.setOnClickListener {
Navigation.findNavController(it).navigate(R.id.navigateToAnotherDebugFragment)
}
} }
} }

@ -2,13 +2,11 @@ package com.example.wikispot.fragments
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.activity.addCallback
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.example.wikispot.R import com.example.wikispot.R
import com.example.wikispot.models_and_adapters.PlacePreviewsAdapter import com.example.wikispot.adapters.PlacePreviewsAdapter
import com.example.wikispot.models_and_adapters.PlaceSupplier import com.example.wikispot.modelsForAdapters.PlaceSupplier
import kotlinx.android.synthetic.main.fragment_explore.* import kotlinx.android.synthetic.main.fragment_explore.*

@ -1,23 +1,62 @@
package com.example.wikispot.fragments package com.example.wikispot.fragments
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.navigation.Navigation import androidx.navigation.Navigation
import com.example.wikispot.IntentsKeys
import com.example.wikispot.R import com.example.wikispot.R
import com.example.wikispot.ThemeOptions
import com.example.wikispot.activities.MainActivity
import com.example.wikispot.modelClasses.SettingsSaveManager
import kotlinx.android.synthetic.main.fragment_settings.* import kotlinx.android.synthetic.main.fragment_settings.*
class settingsFragment : Fragment(R.layout.fragment_settings) { class settingsFragment : Fragment(R.layout.fragment_settings) {
private lateinit var settingsSaveManager: SettingsSaveManager
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
settingsSaveManager = SettingsSaveManager(requireContext())
loadSettings()
debugBtn.setOnClickListener { debugBtn.setOnClickListener {
Navigation.findNavController(it).navigate(R.id.navigateToDebugFragment) Navigation.findNavController(it).navigate(R.id.navigateToDebugFragment)
} }
darkThemeSwitch.setOnCheckedChangeListener { _, isChecked ->
ThemeOptions.darkTheme = isChecked
settingsSaveManager.saveSettings()
restartAppPartially()
}
actionBarSwitch.setOnCheckedChangeListener { _, isChecked ->
ThemeOptions.actionBar = isChecked
settingsSaveManager.saveSettings()
restartAppPartially()
}
} }
private fun loadSettings() {
if (ThemeOptions.darkTheme) {
darkThemeSwitch.isChecked = true
}
if (ThemeOptions.actionBar) {
actionBarSwitch.isChecked = true
}
}
private fun restartAppPartially() {
val intent = Intent(context?.applicationContext, MainActivity::class.java)
intent.putExtra(IntentsKeys.startFragment, "settingsFragment")
startActivity(intent)
activity?.finish()
}
} }

@ -0,0 +1,192 @@
package com.example.wikispot.modelClasses
import android.content.Context
import com.example.wikispot.getStringFromSharedPreferences
import com.example.wikispot.saveString
import com.example.wikispot.showToast
import org.json.JSONArray
import org.json.JSONObject
data class JsonManager(val context: Context, val data: String, val inputType: String = "JSONArray", val debug: Boolean = false) {
var jsonArray: JSONArray? = null
var currentJsonObject: JSONObject? = null
private var currentJsonAttribute0: JSONObject? = null
private var currentJsonAttribute1: JSONArray? = null
init {
if (inputType == "JSONArray") {
jsonArray = JSONArray(data)
try {
currentJsonObject = jsonArray!!.getJSONObject(0)
} catch (exception: Throwable) {}
if (debug) {
println("[debug] Content of received JSONArray is ${jsonArray.toString()}")
}
} else if (inputType == "JSONObject") {
currentJsonObject = JSONObject(data)
if (debug) {
println("[debug] Content of received JSONObject is ${currentJsonObject.toString()}")
}
}
}
fun getJsonObject(i: Int): JSONObject? {
jsonArray?.let {
if ((i >= jsonArray!!.length()) or (i < 0)) {
context.showToast("Index out of range")
} else {
currentJsonObject = jsonArray?.getJSONObject(i)
return currentJsonObject
}
}
if (jsonArray == null) {
context.showToast("Json Array is null")
}
return null
}
fun getAttributeContent(name: String): String {
if (currentJsonObject != null) {
if (currentJsonAttribute0 != null) {
try {
currentJsonAttribute0 = currentJsonAttribute0!!.getJSONObject(name)
return currentJsonAttribute0.toString()
} catch (exception: Throwable) {
try {
currentJsonAttribute1 = currentJsonAttribute0!!.getJSONArray(name)
currentJsonAttribute0 = null
return currentJsonAttribute1.toString()
} catch (exception: Throwable) {
try {
return currentJsonAttribute0!!.get(name).toString()
} catch (exception: Throwable) {
context.showToast("Invalid attribute name")
}
}
}
} else if (currentJsonAttribute1 != null) {
try {
currentJsonAttribute0 = currentJsonAttribute1!!.getJSONObject(name.toInt())
return currentJsonAttribute0.toString()
} catch (exception: Throwable) {
try {
currentJsonAttribute1 = currentJsonAttribute1!!.getJSONArray(name.toInt())
currentJsonAttribute0 = null
return currentJsonAttribute1.toString()
} catch (exception: Throwable) {
try {
return currentJsonAttribute1!!.get(name.toInt()).toString()
} catch (exception: Throwable) {
context.showToast("Invalid attribute name")
}
}
}
} else {
try {
currentJsonAttribute0 = currentJsonObject!!.getJSONObject(name)
return currentJsonAttribute0.toString()
} catch (exception: Throwable) {
try {
currentJsonAttribute1 = currentJsonObject!!.getJSONArray(name)
currentJsonAttribute0 = null
return currentJsonAttribute1.toString()
} catch (exception: Throwable) {
try {
return currentJsonObject!!.get(name).toString()
} catch (exception: Throwable) {
context.showToast("Invalid attribute name")
}
}
}
}
} else {
context.showToast("Json file is null")
}
return ""
}
fun getAttributeContentByPath(path: String): String {
val steps = path.split("/")
val currentJsonAttributesBackup = listOf(currentJsonAttribute0, currentJsonAttribute1) // backing up selected jsonAttributes
// getting the attribute
clearSelectedAttribute()
var result: Any? = null
for (step in steps) {
try {
result = getAttributeContent(step)
} catch (exception: Throwable) {
context.showToast("Invalid path")
// loading back saved json attributes
currentJsonAttribute0 = currentJsonAttributesBackup[0] as JSONObject?
currentJsonAttribute1 = currentJsonAttributesBackup[1] as JSONArray?
return ""
}
}
// loading back saved json attributes
currentJsonAttribute0 = currentJsonAttributesBackup[0] as JSONObject?
currentJsonAttribute1 = currentJsonAttributesBackup[1] as JSONArray?
// returning result
return result.toString()
}
fun clearSelectedAttribute() {
currentJsonAttribute0 = null
currentJsonAttribute1 = null
}
fun getLengthOfJsonArray(): Int {
return if (jsonArray != null) {
if (debug) {
println("[debug] Length of json array is ${jsonArray!!.length()}")
}
jsonArray!!.length()
} else {
println("[debug] Length of json array is 0")
0
}
}
fun getCurrentJsonAttributeContent(): String {
if (currentJsonAttribute0 != null) {
return currentJsonAttribute0.toString()
} else if (currentJsonAttribute1 != null) {
return currentJsonAttribute1.toString()
}
return "get json attribute first"
}
// saving and loading
fun saveJson(accessKey: String) {
// finding data that could be saved
if (jsonArray != null) {
context.saveString(accessKey, jsonArray.toString(), "jsonStrings")
} else if (currentJsonObject != null) {
context.saveString(accessKey, currentJsonObject.toString(), "jsonStrings")
} else if (currentJsonAttribute0 != null) {
context.saveString(accessKey, currentJsonAttribute0.toString(), "jsonStrings")
} else if (currentJsonAttribute1 != null) {
context.saveString(accessKey, currentJsonAttribute1.toString(), "jsonStrings")
} else {
context.showToast("Nothing to save")
}
}
fun loadJson(context: Context, accessKey: String, inputType: String = "JSONArray", debug: Boolean = false): JsonManager {
return JsonManager(context, context.getStringFromSharedPreferences(accessKey, "jsonStrings"), inputType, debug)
}
}

@ -0,0 +1,205 @@
package com.example.wikispot.modelClasses
import android.app.Activity
import android.content.Context
import android.widget.TextView
import com.example.wikispot.ServerManagement
import com.example.wikispot.receiveData
import okhttp3.*
import org.json.JSONArray
import java.io.IOException
class ServerManager {
private var activityConnections = mutableListOf<ActivityConnection>()
private var viewConnections = mutableListOf<ViewConnection>()
fun getData(activity: Activity, context: Context, serverId: Int, path: String, attributePath: String, getWholeContent: Boolean=false, numberOfAttempts: Int=2) {
val dataRequestThread = Thread(DataRequest(activity, context, serverId, path, attributePath, getWholeContent, numberOfAttempts))
dataRequestThread.start()
}
inner class DataRequest(val activity: Activity, val context: Context, val serverId: Int, val path: String="", val attributePath: String, var getWholeContent: Boolean=false, val numberOfAttempts: Int=2): Runnable{
override fun run() {
for (n in 0 until numberOfAttempts) {
var url = "http://192.168.1.230:8000/devices_list"
if (path != "") {
url = "http://192.168.1.230:8000/files/$serverId/$path"
}
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
response.body?.let {
val receivedString = response.body!!.string()
if (receivedString == "Internal Server Error") {
return
}
try {
JSONArray(receivedString)
val jsonManager = JsonManager(context, receivedString)
if (path == "") {
jsonManager.getJsonObject(serverId)
} else {
if (attributePath == "") {
getWholeContent = true
}
}
if (getWholeContent) {
activity.receiveData(jsonManager.currentJsonObject.toString())
println("[debug] testing ${activity.localClassName} ; ${activity.componentName} ; ${activity.packageName}")
} else if(attributePath != "") {
activity.receiveData(jsonManager.getAttributeContentByPath(attributePath))
} else {
println("[debug] path or whole content needs to be chosen")
}
} catch (exception: Throwable) {
activity.receiveData(receivedString)
}
}
}
override fun onFailure(call: Call, e: IOException) {
println("Request Failed")
println(e)
}
})
Thread.sleep(ServerManagement.dataRequestOnAttemptWait)
}
}
}
// connections
fun deleteConnection(connectionName: String, connectionType: String="any") { // other types are any, activity and view
if ((connectionType == "any") or (connectionType == "activity")) {
for (i in 0 until activityConnections.size) { // checking in connections
if (activityConnections[i].connectionName == connectionName) {
activityConnections[i].running = false
activityConnections.removeAt(i)
}
}
}
if ((connectionType == "any") or (connectionType == "view")) {
for (i in 0 until viewConnections.size) { // checking in connections
if (viewConnections[i].connectionName == connectionName) {
viewConnections[i].running = false
viewConnections.removeAt(i)
}
}
}
}
fun addActivityConnection(activity: Activity, connectionName: String, serverId: Int, path: String?=null) {
activityConnections.add(ActivityConnection(activity, connectionName, serverId, path))
}
inner class ActivityConnection(val activity: Activity, val connectionName: String, val serverId: Int, val path: String?=null) {
var running = true
init {
val checkingServerDataThread = Thread(CheckingServerData())
checkingServerDataThread.start()
}
inner class CheckingServerData : Runnable {
override fun run() {
while (running) {
println("[debug] connection thread running")
Thread.sleep(ServerManagement.activityConnectionOnCheckWait)
}
}
}
}
fun addViewConnection(context: Context, view: TextView, connectionName: String, serverId: Int, path: String="", attributePath: String, getWholeContent: Boolean=false) {
viewConnections.add(ViewConnection(context, view, connectionName, serverId, path, attributePath, getWholeContent))
}
inner class ViewConnection(val context: Context, val view: TextView, val connectionName: String, val serverId: Int, val path: String="", var attributePath: String, var getWholeContent: Boolean=false) {
var running = true
init {
val checkingServerDataThread = Thread(CheckingServerData())
checkingServerDataThread.start()
}
inner class CheckingServerData: Runnable {
override fun run() {
while (running) {
var url = "http://192.168.1.230:8000/devices_list"
if (path != "") {
url = "http://192.168.1.230:8000/files/$serverId/$path"
}
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
response.body?.let {
val receivedString = response.body!!.string()
if (receivedString == "Internal Server Error") {
return
}
try {
JSONArray(receivedString)
val jsonManager = JsonManager(context, receivedString)
if (path == "") {
jsonManager.getJsonObject(serverId)
} else {
if (attributePath == "") {
throw Throwable()
}
}
if (getWholeContent) {
view.post {
view.text = jsonManager.currentJsonObject.toString()
}
} else if(attributePath != "") {
view.post {
view.text = jsonManager.getAttributeContentByPath(attributePath)
}
} else {
println("[debug] path or whole content needs to be chosen")
}
} catch (exception: Throwable) {
view.post {
view.text = receivedString
}
}
}
}
override fun onFailure(call: Call, e: IOException) {
println("Request Failed")
println(e)
}
})
Thread.sleep(ServerManagement.viewConnectionOnCheckWait)
}
}
}
}
}

@ -0,0 +1,25 @@
package com.example.wikispot.modelClasses
import android.content.Context
import com.example.wikispot.ThemeOptions
class SettingsSaveManager(val context: Context) {
fun loadSettings() {
val sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
ThemeOptions.darkTheme = sharedPreferences.getBoolean("darkMode", ThemeOptions.darkTheme)
ThemeOptions.actionBar = sharedPreferences.getBoolean("actionBar", ThemeOptions.actionBar)
}
fun saveSettings() {
val sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.apply{
putBoolean("darkMode", ThemeOptions.darkTheme)
putBoolean("actionBar", ThemeOptions.actionBar)
}.apply()
}
}

@ -1,4 +1,4 @@
package com.example.wikispot.models_and_adapters package com.example.wikispot.modelsForAdapters
import android.media.Image import android.media.Image

@ -0,0 +1,32 @@
package com.example.wikispot
import com.example.wikispot.modelClasses.ServerManager
object ManifestRelatedVariables {
val REQUEST_READ_EXTERNAL = 1
}
object IntentsKeys {
const val startFragment = "start_fragment"
}
object ServerManagement {
val serverManager = ServerManager()
const val activityConnectionOnCheckWait: Long = 4000
const val viewConnectionOnCheckWait: Long = 5000
const val dataRequestOnAttemptWait: Long = 2000
}
object ThemeOptions {
var darkTheme = false
var actionBar = true
}

@ -4,7 +4,7 @@ json_list = []
def init(): def init():
global json_list global json_list
json_list = eval(requests.get("http://192.168.1.120:8000/devices_list").text) json_list = eval(requests.get("http://192.168.1.230:8000/devices_list").text)
def get_length(): def get_length():

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:background="#E04C4C"
tools:context=".fragments.anotherDebugFragment">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Another Debug Fragment"
android:textColor="#FFFFFF"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/goFirstDegubFragmentBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:text="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
<Button
android:id="@+id/generateAndSaveDataBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="Generate and save data"
app:layout_constraintEnd_toStartOf="@+id/goFirstDegubFragmentBtn"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
<Button
android:id="@+id/loadAndShowDataBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:text="Load and Show data"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/generateAndSaveDataBtn" />
<ScrollView
android:id="@+id/scrollView4"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:background="#E66C6C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintStart_toEndOf="@+id/loadAndShowDataBtn"
app:layout_constraintTop_toBottomOf="@+id/goFirstDegubFragmentBtn">
<TextView
android:id="@+id/dataContentView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="data content"
android:textAlignment="center" />
</ScrollView>
<CheckBox
android:id="@+id/wholeContentCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:shadowColor="#B4B4B4"
android:text="Whole Content"
android:textColor="#FFFFFF"
android:textColorHighlight="#FFFFFF"
android:textColorHint="#FFFFFF"
android:textColorLink="#FFFFFF"
app:layout_constraintStart_toStartOf="@+id/attributePathInput"
app:layout_constraintTop_toBottomOf="@+id/attributePathInput"
app:useMaterialThemeColors="false" />
<EditText
android:id="@+id/attributePathInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:ems="10"
android:hint="attribute path"
android:inputType="textPersonName"
app:layout_constraintStart_toStartOf="@+id/loadAndShowDataBtn"
app:layout_constraintTop_toBottomOf="@+id/loadAndShowDataBtn" />
<Button
android:id="@+id/createViewConnectionBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="8dp"
android:text="Create View Connection"
android:textSize="12sp"
app:layout_constraintStart_toEndOf="@+id/wholeContentCheckBox"
app:layout_constraintTop_toBottomOf="@+id/attributePathInput" />
<Button
android:id="@+id/stopConnectionBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Stop Connection"
android:textSize="10sp"
app:layout_constraintBottom_toBottomOf="@+id/attributePathInput"
app:layout_constraintEnd_toEndOf="@+id/createViewConnectionBtn"
app:layout_constraintStart_toEndOf="@+id/attributePathInput" />
<EditText
android:id="@+id/filePathInput"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:ems="10"
android:hint="file path"
android:inputType="textPersonName"
app:layout_constraintBottom_toTopOf="@+id/attributePathInput"
app:layout_constraintStart_toStartOf="@+id/loadAndShowDataBtn"
app:layout_constraintTop_toBottomOf="@+id/loadAndShowDataBtn" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -43,10 +43,10 @@
app:layout_constraintTop_toBottomOf="@+id/getDataBtn" /> app:layout_constraintTop_toBottomOf="@+id/getDataBtn" />
<Button <Button
android:id="@+id/displayJsonFileBtn" android:id="@+id/getJsonFileBtn"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Display Json File" android:text="Get Json File"
app:layout_constraintStart_toStartOf="@+id/idInput" app:layout_constraintStart_toStartOf="@+id/idInput"
app:layout_constraintTop_toBottomOf="@+id/idInput" /> app:layout_constraintTop_toBottomOf="@+id/idInput" />
@ -59,7 +59,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/displayJsonFileBtn"> app:layout_constraintTop_toBottomOf="@+id/getJsonFileBtn">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -67,11 +67,12 @@
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/jsonFileOutputView" android:id="@+id/jsonFileContentView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="json output" android:text="json content"
android:textAlignment="center" android:textAlignment="center"
android:textSize="18sp"
tools:layout_editor_absoluteX="254dp" tools:layout_editor_absoluteX="254dp"
tools:layout_editor_absoluteY="95dp" /> tools:layout_editor_absoluteY="95dp" />
@ -86,8 +87,80 @@
android:layout_marginLeft="24dp" android:layout_marginLeft="24dp"
android:text="Amount of json's: 0" android:text="Amount of json's: 0"
android:textSize="24sp" android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@+id/displayJsonFileBtn" app:layout_constraintBottom_toTopOf="@+id/getJsonFileBtn"
app:layout_constraintStart_toEndOf="@+id/idInput" app:layout_constraintStart_toEndOf="@+id/idInput"
app:layout_constraintTop_toBottomOf="@+id/getDataBtn" /> app:layout_constraintTop_toBottomOf="@+id/getDataBtn" />
<Button
android:id="@+id/getAttributeContentBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="Get Attribute "
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/scrollView3" />
<EditText
android:id="@+id/attributeNameInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:ems="10"
android:hint=" attribute name"
android:inputType="textPersonName"
app:layout_constraintStart_toStartOf="@+id/getAttributeContentBtn"
app:layout_constraintTop_toBottomOf="@+id/getAttributeContentBtn" />
<ScrollView
android:layout_width="380dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:background="#FF6C6C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/attributeNameInput">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/attributeContentView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="attribute content"
android:textAlignment="center"
android:textSize="18sp"
android:gravity="center_horizontal" />
</LinearLayout>
</ScrollView>
<Button
android:id="@+id/clearAttributeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="Clear Attribute"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/getAttributeContentBtn"
app:layout_constraintTop_toBottomOf="@+id/scrollView3" />
<Button
android:id="@+id/goSecondDebugFragmentBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:text="2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -7,6 +7,20 @@
android:background="#F57C00" android:background="#F57C00"
tools:context=".fragments.settingsFragment"> tools:context=".fragments.settingsFragment">
<TextView
android:id="@+id/actionBarThemeSwitchText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="32dp"
android:text="Action Bar"
android:textColor="#FFFFFF"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/darkThemeSwitchText" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -24,8 +38,41 @@
android:id="@+id/debugBtn" android:id="@+id/debugBtn"
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="30dp" android:layout_height="30dp"
app:srcCompat="@drawable/debug_vector_asset"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/debug_vector_asset" />
<TextView
android:id="@+id/darkThemeSwitchText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="88dp"
android:text="Dark theme"
android:textColor="#FFFFFF"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<Switch
android:id="@+id/darkThemeSwitch"
android:layout_width="50dp"
android:layout_height="21dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
app:layout_constraintBottom_toBottomOf="@+id/darkThemeSwitchText"
app:layout_constraintStart_toEndOf="@+id/darkThemeSwitchText"
app:layout_constraintTop_toTopOf="@+id/darkThemeSwitchText" />
<Switch
android:id="@+id/actionBarSwitch"
android:layout_width="50dp"
android:layout_height="21dp"
app:layout_constraintBottom_toBottomOf="@+id/actionBarThemeSwitchText"
app:layout_constraintEnd_toEndOf="@+id/darkThemeSwitch"
app:layout_constraintStart_toStartOf="@+id/darkThemeSwitch"
app:layout_constraintTop_toTopOf="@+id/actionBarThemeSwitchText" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -53,5 +53,18 @@
android:id="@+id/debugFragment" android:id="@+id/debugFragment"
android:name="com.example.wikispot.fragments.debugFragment" android:name="com.example.wikispot.fragments.debugFragment"
android:label="fragment_debug" android:label="fragment_debug"
tools:layout="@layout/fragment_debug" /> tools:layout="@layout/fragment_debug" >
<action
android:id="@+id/navigateToAnotherDebugFragment"
app:destination="@id/anotherDebugFragment" />
</fragment>
<fragment
android:id="@+id/anotherDebugFragment"
android:name="com.example.wikispot.fragments.anotherDebugFragment"
android:label="fragment_another_debug"
tools:layout="@layout/fragment_another_debug" >
<action
android:id="@+id/navigateBackToDebugFragment"
app:destination="@id/debugFragment" />
</fragment>
</navigation> </navigation>

@ -1,6 +1,20 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.WikiSpot" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <style name="Theme.WikiSpot" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<style name="Theme.WikiSpotWithActionBar" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item> <item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorPrimaryVariant">@color/purple_700</item>

@ -11,6 +11,8 @@
<item name="colorOnSecondary">@color/black</item> <item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. --> <!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<item name="android:windowFullscreen">true</item>
</style> </style>
<style name="Theme.WikiSpotWithActionBar" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <style name="Theme.WikiSpotWithActionBar" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
@ -26,4 +28,33 @@
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
</style> </style>
<!-- Dark themes below -->
<style name="Theme.WikiSpotDark" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">#B078F4</item>
<item name="colorPrimaryVariant">#5100B3</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<item name="android:windowFullscreen">true</item>
</style>
<style name="Theme.WikiSpotWithActionBarDark" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">#B078F4</item>
<item name="colorPrimaryVariant">#5100B3</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
</style>
</resources> </resources>

@ -4,12 +4,10 @@ buildscript {
repositories { repositories {
google() google()
jcenter() jcenter()
maven {url "https://chaquo.com/maven"}
} }
dependencies { dependencies {
classpath "com.android.tools.build:gradle:4.1.1" classpath "com.android.tools.build:gradle:4.1.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.chaquo.python:gradle:9.1.0"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files