diff --git a/app/WikiSpot/app/build.gradle b/app/WikiSpot/app/build.gradle index c0f702e..b6211fc 100644 --- a/app/WikiSpot/app/build.gradle +++ b/app/WikiSpot/app/build.gradle @@ -53,4 +53,7 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + + implementation 'com.github.bumptech.glide:glide:4.12.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' } \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/ic_launcher-playstore.png b/app/WikiSpot/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..d39dc90 Binary files /dev/null and b/app/WikiSpot/app/src/main/ic_launcher-playstore.png differ diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/activities/MainActivity.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/activities/MainActivity.kt index e9e7b8c..b7417ac 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/activities/MainActivity.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/activities/MainActivity.kt @@ -1,20 +1,24 @@ package com.example.wikispot.activities import android.content.Intent +import android.graphics.Bitmap import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.navigation.findNavController import androidx.navigation.ui.setupWithNavController -import com.example.wikispot.* +import com.example.wikispot.IntentsKeys +import com.example.wikispot.R +import com.example.wikispot.ServerManagement import com.example.wikispot.fragments.* +import com.example.wikispot.getThemeId import com.example.wikispot.modelClasses.JsonManager +import com.example.wikispot.modelClasses.JsonManagerLite import com.example.wikispot.modelClasses.SettingsSaveManager import com.example.wikispot.modelsForAdapters.PlacePreview import com.example.wikispot.modelsForAdapters.PlaceSupplier import kotlinx.android.synthetic.main.activity_main.* -import kotlinx.android.synthetic.main.fragment_home.* class MainActivity : AppCompatActivity() { @@ -51,12 +55,7 @@ class MainActivity : AppCompatActivity() { when (mainFragmentHost.childFragmentManager.fragments[0]) { is chatFragment -> {} is exploreFragment -> {} - is homeFragment -> { - val view = mainFragmentHost.childFragmentManager.fragments[0].homeFragmentTextIdTest - view.post { - view.text = data - } - } + is homeFragment -> {} is mapFragment -> {} is settingsFragment -> {} } @@ -64,13 +63,15 @@ class MainActivity : AppCompatActivity() { } - //ServerManagement.serverManager.addReceiverConnection(dataReceiver, this, "mainConnection", 0, "test0.json") + ServerManagement.serverManager.addReceiverConnection(dataReceiver, this, "mainConnection", 0, "test0.json") connectExploreFragmentAdapterModel() } override fun onPause() { - super.onPause() + PlaceSupplier.saveToCache(this) ServerManagement.serverManager.deleteConnection("mainConnection") + ServerManagement.serverManager.deleteConnection("exploreListConnection") + super.onPause() } private fun handleExtras() { @@ -90,27 +91,69 @@ class MainActivity : AppCompatActivity() { } private fun connectExploreFragmentAdapterModel () { + // loading from cache + PlaceSupplier.loadFromCache(this) + + // connecting to server val dataReceiver: (String) -> Unit = {data: String -> val json = JsonManager(this, data) - for (i in 0 until json.getLengthOfJsonArray()) { // todo change to 1 + + if (PlaceSupplier.controlJson == null) { + PlaceSupplier.controlJson = JsonManagerLite(data) + } + + for (i in 1 until json.getLengthOfJsonArray()) { // todo change to 1 + json.getJsonObject(i) + val id = json.getAttributeContent("ID").toInt() json.getAttributeContent("description") val title = json.getAttributeContent("title") val shortDescription = json.getAttributeContent("description_s") - val place = PlacePreview(title, shortDescription) - if (!PlaceSupplier.places.contains(place)) { + val place = PlacePreview(title, shortDescription, null, id) + + if (!PlaceSupplier.checkIfContains(place)) { + + val imageReceiver: (Bitmap) -> Unit = {bitmap: Bitmap -> + place.img = bitmap + } + + ServerManagement.serverManager.getImage(imageReceiver, id, "test.png", 3) + PlaceSupplier.appendPlace(place) + } else { + val containingPlace = PlaceSupplier.getContainingInstance(place) + if ((containingPlace != null) and (containingPlace?.img == null)) { + val imageReceiver: (Bitmap) -> Unit = {bitmap: Bitmap -> + containingPlace?.img = bitmap + } + + ServerManagement.serverManager.getImage(imageReceiver, id, "test.png", 3) + } } + + json.clearSelectedAttribute() } } - ServerManagement.serverManager.addReceiverConnection(dataReceiver, this, "exploreListConnection", 0, "", "GET_JSON_ARRAY") + ServerManagement.serverManager.addReceiverConnection(dataReceiver, this, "exploreListConnection", 0, "", "GET_WHOLE_ARRAY", 10000) } - private fun restartAppPartially() { + private fun restartAppPartially() { // todo remove if not used val intent = Intent(applicationContext, MainActivity::class.java) - intent.putExtra(IntentsKeys.startFragment, "settingsFragment") + var currentNavHostFragmentName = "homeFragment" + + try { + when (mainFragmentHost.childFragmentManager.fragments[0]) { + is chatFragment -> {currentNavHostFragmentName = "chatFragment"} + is exploreFragment -> {currentNavHostFragmentName= "exploreFragment"} + is homeFragment -> {currentNavHostFragmentName = "homeFragment"} + is mapFragment -> {currentNavHostFragmentName = "mapFragment"} + is settingsFragment -> {currentNavHostFragmentName = "settingsFragment"} + } + } catch (e: Throwable) { println(e) } + + intent.putExtra(IntentsKeys.startFragment, currentNavHostFragmentName) startActivity(intent) finish() diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/adapters/PlacePreviewsAdapter.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/adapters/PlacePreviewsAdapter.kt index 2693e9d..dba3e0e 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/adapters/PlacePreviewsAdapter.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/adapters/PlacePreviewsAdapter.kt @@ -4,9 +4,12 @@ import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.navigation.Navigation import androidx.recyclerview.widget.RecyclerView import com.example.wikispot.R +import com.example.wikispot.ServerManagement import com.example.wikispot.modelsForAdapters.PlacePreview +import com.example.wikispot.showToast import kotlinx.android.synthetic.main.explore_list_item.view.* @@ -18,6 +21,10 @@ class PlacePreviewsAdapter(private val context: Context, private val placePrevie var pos: Int = 0 init { + itemView.setOnClickListener { + ServerManagement.selectedServerId = currentPlacePreview?.id!! + Navigation.findNavController(it).navigate(R.id.navigateToInfoFragment) + } } fun setData(placePreview: PlacePreview?, pos: Int) { @@ -25,7 +32,7 @@ class PlacePreviewsAdapter(private val context: Context, private val placePrevie itemView.item_title.text = placePreview.title itemView.item_description.text = placePreview.description placePreview.img?.let { - // TODO set image somehow + itemView.item_img.setImageBitmap(placePreview.img) } } diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/exploreFragment.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/exploreFragment.kt index 1901784..56a6cb0 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/exploreFragment.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/exploreFragment.kt @@ -1,10 +1,15 @@ package com.example.wikispot.fragments +import android.content.Intent import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager +import com.example.wikispot.GeneralVariables +import com.example.wikispot.IntentsKeys import com.example.wikispot.R +import com.example.wikispot.ServerManagement +import com.example.wikispot.activities.MainActivity import com.example.wikispot.adapters.PlacePreviewsAdapter import com.example.wikispot.modelsForAdapters.PlaceSupplier import kotlinx.android.synthetic.main.fragment_explore.* diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/homeFragment.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/homeFragment.kt index ef6b3b9..532e7ee 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/homeFragment.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/homeFragment.kt @@ -1,21 +1,50 @@ package com.example.wikispot.fragments import android.os.Bundle -import androidx.fragment.app.Fragment -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup +import androidx.fragment.app.Fragment import com.example.wikispot.R -import com.example.wikispot.getStringFromSharedPreferences -import com.example.wikispot.saveString +import com.example.wikispot.ServerManagement +import com.example.wikispot.modelClasses.JsonManager import kotlinx.android.synthetic.main.fragment_home.* +import kotlinx.android.synthetic.main.fragment_info.view.* class homeFragment : Fragment(R.layout.fragment_home) { + var infoFragmentLoadedIn = false + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - //loadCache() + loadCache() + } + + override fun onResume() { + super.onResume() + + // connecting to server + val dataReceiver: (String) -> Unit = {data: String -> + try { + val json = JsonManager(requireContext(), data) + + json.findJsonObjectByAttribute("ID", json.getAttributeContent("connected_id")) + + if (!infoFragmentLoadedIn) { + + infoFragmentLoadedIn = true + + homeFragmentInnerFragment.post { + homeFragmentInnerFragment.let { fragment -> + fragment.mainTitle.text = json.getAttributeContentByPath("description/title") + fragment.mainDescription.text = json.getAttributeContentByPath("description/description_l") + } + } + } + } catch (e: Throwable) { println(e) } + } + + ServerManagement.serverManager.getData(dataReceiver, requireContext(), 0, "", "GET_JSON_ARRAY", 3) + } override fun onPause() { @@ -23,11 +52,7 @@ class homeFragment : Fragment(R.layout.fragment_home) { saveCache() } - private fun loadCache() { - homeFragmentTextIdTest.text = requireContext().getStringFromSharedPreferences("title", "homeFragmentCache" ) - } + private fun loadCache() {} - private fun saveCache() { - requireContext().saveString("title", homeFragmentTextIdTest.text.toString(), "homeFragmentCache") - } + private fun saveCache() {} } \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/infoFragment.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/infoFragment.kt new file mode 100644 index 0000000..4ee6039 --- /dev/null +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/fragments/infoFragment.kt @@ -0,0 +1,19 @@ +package com.example.wikispot.fragments + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.wikispot.R +import com.example.wikispot.modelClasses.JsonManager +import kotlinx.android.synthetic.main.fragment_info.* + + +class infoFragment() : Fragment(R.layout.fragment_info) { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + } + +} \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/JsonManager.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/JsonManager.kt index a6f9b49..bed1385 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/JsonManager.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/JsonManager.kt @@ -7,7 +7,7 @@ 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) { +data class JsonManager(private val context: Context, val data: String, val inputType: String = "JSONArray", val debug: Boolean = false) { var jsonArray: JSONArray? = null var currentJsonObject: JSONObject? = null @@ -66,7 +66,9 @@ data class JsonManager(val context: Context, val data: String, val inputType: St try { return currentJsonAttribute0!!.get(name).toString() } catch (exception: Throwable) { - context.showToast("Invalid attribute name") + if (debug) { + context.showToast("Invalid attribute name: $name") + } } } } @@ -83,7 +85,9 @@ data class JsonManager(val context: Context, val data: String, val inputType: St try { return currentJsonAttribute1!!.get(name.toInt()).toString() } catch (exception: Throwable) { - context.showToast("Invalid attribute name") + if (debug) { + context.showToast("Invalid attribute name: $name") + } } } } @@ -100,13 +104,17 @@ data class JsonManager(val context: Context, val data: String, val inputType: St try { return currentJsonObject!!.get(name).toString() } catch (exception: Throwable) { - context.showToast("Invalid attribute name") + if (debug) { + context.showToast("Invalid attribute name: $name") + } } } } } } else { - context.showToast("Json file is null") + if (debug) { + context.showToast("Invalid attribute name: $name") + } } return "" @@ -166,6 +174,30 @@ data class JsonManager(val context: Context, val data: String, val inputType: St return "get json attribute first" } + fun findJsonObjectByAttribute(attributePath: String, value: Any): String { + val currentJsonObjectSave = currentJsonObject + + for (i in 0 until getLengthOfJsonArray()) { + + getJsonObject(i) + + val attributeContent = getAttributeContentByPath(attributePath) + + if (attributeContent != "null") { + + if (attributeContent == value.toString()) { + return currentJsonObject.toString() + } + + } + + } + + currentJsonObject = currentJsonObjectSave + return currentJsonObject.toString() + + } + // saving and loading fun saveJson(accessKey: String) { diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/JsonManagerLite.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/JsonManagerLite.kt new file mode 100644 index 0000000..a75ab67 --- /dev/null +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/JsonManagerLite.kt @@ -0,0 +1,139 @@ +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 JsonManagerLite(val data: String, val inputType: String = "JSONArray") { + + 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) {} + + } else if (inputType == "JSONObject") { + currentJsonObject = JSONObject(data) + } + } + + fun getJsonObject(i: Int): JSONObject? { + jsonArray?.let { + currentJsonObject = jsonArray?.getJSONObject(i) + return currentJsonObject + } + + 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) { } + } + } + } 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) { } + } + } + } 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) { } + } + } + } + } + + 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) { + // 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) { + jsonArray!!.length() + } else { + 0 + } + } + + fun getCurrentJsonAttributeContent(): String { + if (currentJsonAttribute0 != null) { + return currentJsonAttribute0.toString() + } else if (currentJsonAttribute1 != null) { + return currentJsonAttribute1.toString() + } + return "get json attribute first" + } +} diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/ServerManager.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/ServerManager.kt index eb31ba7..e89656d 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/ServerManager.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelClasses/ServerManager.kt @@ -1,12 +1,15 @@ package com.example.wikispot.modelClasses import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory import android.widget.TextView import com.example.wikispot.ServerManagement import okhttp3.* import org.json.JSONArray import org.json.JSONObject import java.io.IOException +import java.io.InputStream class ServerManager { @@ -43,6 +46,10 @@ class ServerManager { val jsonManager = JsonManager(context, receivedString) if (path == "") { + if (attributePath == "GET_JSON_ARRAY") { + dataReceiver(jsonManager.jsonArray.toString()) + return + } jsonManager.getJsonObject(serverId) } else { if (attributePath == "") { @@ -86,44 +93,74 @@ class ServerManager { } } + fun getImage(imageReceiver: (Bitmap) -> Unit, serverId: Int, path: String, numberOfAttempts: Int) { + val imageRequestThread = Thread(ImageRequest(imageReceiver, serverId, path, numberOfAttempts)) + imageRequestThread.start() + } + + inner class ImageRequest(val imageReceiver: (Bitmap) -> Unit, val serverId: Int, val path: String, private val numberOfAttempts: Int): Runnable { + override fun run() { + for (i in 0 until numberOfAttempts) { + val url = "${ServerManagement.baseUrl}files/$serverId/$path" + + try { + val inputStream = java.net.URL(url).openStream() + val bitmap = BitmapFactory.decodeStream(inputStream) + + imageReceiver(bitmap) + } catch (e: Throwable) { println(e) } + + Thread.sleep(ServerManagement.imageRequestOnAttemptWait) + } + } + } + // connections fun clearConnections() { for (i in 0 until receiverConnections.size) { - receiverConnections[i].running = false - receiverConnections.removeAt(i) + try { + receiverConnections[i].running = false + receiverConnections.removeAt(i) + } catch (e: Throwable) { println("In clearConnections: $e") } } for (i in 0 until viewConnections.size) { - viewConnections[i].running = false - viewConnections.removeAt(i) + try { + viewConnections[i].running = false + viewConnections.removeAt(i) + } catch (e: Throwable) { println("In clearConnections: $e") } } } 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 receiverConnections.size) { // checking in connections - if (receiverConnections[i].connectionName == connectionName) { - receiverConnections[i].running = false - receiverConnections.removeAt(i) - } + try { + if (receiverConnections[i].connectionName == connectionName) { + receiverConnections[i].running = false + receiverConnections.removeAt(i) + } + } catch (e: Throwable) { println("In deleteConnection: $e") } } } 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) - } + try { + if (viewConnections[i].connectionName == connectionName) { + viewConnections[i].running = false + viewConnections.removeAt(i) + } + } catch (e: Throwable) { println("In deleteConnection: $e") } } } } - fun addReceiverConnection(dataReceiver: (String) -> Unit, context: Context, connectionName: String, serverId: Int, path: String?=null, attributePath: String="") { - receiverConnections.add(ReceiverConnection(dataReceiver, context, connectionName, serverId, path, attributePath)) + fun addReceiverConnection(dataReceiver: (String) -> Unit, context: Context, connectionName: String, serverId: Int, path: String?=null, attributePath: String="", waitTime: Long=ServerManagement.receiverConnectionOnCheckWait) { + receiverConnections.add(ReceiverConnection(dataReceiver, context, connectionName, serverId, path, attributePath, waitTime)) } - inner class ReceiverConnection(val dataReceiver: (String) -> Unit, val context: Context, val connectionName: String, val serverId: Int, val path: String?=null, val attributePath: String) { + inner class ReceiverConnection(val dataReceiver: (String) -> Unit, val context: Context, val connectionName: String, val serverId: Int, val path: String?=null, val attributePath: String, val waitTime: Long) { var running = true @@ -157,7 +194,7 @@ class ServerManager { val jsonManager = JsonManager(context, receivedString) if (path == "") { - if (attributePath == "GET_JSON_ARRAY") { + if (attributePath == "GET_WHOLE_ARRAY") { dataReceiver(jsonManager.jsonArray.toString()) return } @@ -199,7 +236,7 @@ class ServerManager { } }) - Thread.sleep(ServerManagement.receiverConnectionOnCheckWait) + Thread.sleep(waitTime) } } } @@ -245,6 +282,10 @@ class ServerManager { val jsonManager = JsonManager(context, receivedString) if (path == "") { + if (attributePath == "GET_WHOLE_ARRAY") { + view.text = jsonManager.jsonArray.toString() + return + } jsonManager.getJsonObject(serverId) } else { if (attributePath == "") { diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/modelsForAdapters/ExploreListModel.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelsForAdapters/ExploreListModel.kt index 8c530e5..e11ecd1 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/modelsForAdapters/ExploreListModel.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/modelsForAdapters/ExploreListModel.kt @@ -1,8 +1,15 @@ package com.example.wikispot.modelsForAdapters +import android.content.Context +import android.graphics.Bitmap import android.media.Image +import com.example.wikispot.getStringFromSharedPreferences +import com.example.wikispot.modelClasses.JsonManager +import com.example.wikispot.modelClasses.JsonManagerLite +import com.example.wikispot.saveString +import org.json.JSONArray -data class PlacePreview(var title: String, var description: String, var img: Image? = null) { +data class PlacePreview(var title: String, var description: String, var img: Bitmap? = null, val id: Int?=null) { init { val words = description.split(" ") @@ -11,11 +18,15 @@ data class PlacePreview(var title: String, var description: String, var img: Ima for (word in words) { if (lastLine.length + word.length < 40) { - lastLine += " $word" - description += " $word" + if (lastLine != "") { + lastLine += " " + description += " " + } + lastLine += word + description += word } else { - description += "\n $word" - lastLine = " $word" + description += "\n$word" + lastLine = word } } } @@ -23,18 +34,9 @@ data class PlacePreview(var title: String, var description: String, var img: Ima object PlaceSupplier { - var places = arrayOf( - PlacePreview("Castle", "Its ruins had been repaired to stable state."), - PlacePreview("Library", "You can find books here."), - PlacePreview("Bakery", "You can buy bread here."), - PlacePreview("School", "You can learn stuff here."), - PlacePreview("Castle", "Its ruins had been repaired to stable state."), - PlacePreview("Library", "You can find books here."), - PlacePreview("Bakery", "You can buy bread here."), - PlacePreview("School", "You can learn stuff here."), - PlacePreview("Library", "You can find books here."), - PlacePreview("Bakery", "You can buy bread here.") - ) + var controlJson: JsonManagerLite? = null + + var places = arrayOf() fun appendPlace(place: PlacePreview) { val array = places.copyOf(places.size + 1) @@ -42,4 +44,83 @@ object PlaceSupplier { places = array } + fun checkIfContains(place: PlacePreview): Boolean { + for (n in places.indices) { + places[n]?.let { + if (places[n]?.title == place.title) { + if (places[n]?.description == place.description) { + return true + } + } + } + } + return false + } + + fun getContainingInstance(place: PlacePreview): PlacePreview? { + for (n in places.indices) { + places[n]?.let { + if (places[n]?.title == place.title) { + if (places[n]?.description == place.description) { + return places[n] + } + } + } + } + return null + } + + // loading from and saving to cache + fun loadFromCache(context: Context) { + println("loading") + var save = context.getStringFromSharedPreferences("placePreviews", "exploreFragmentCache") + if (save.isEmpty()) { + save = "[]" + } + val jsonManager = JsonManager(context, save) + for (n in 0 until jsonManager.getLengthOfJsonArray()) { + val savedData = jsonManager.jsonArray?.get(n).toString().split("|||||") + val place = PlacePreview(savedData[0], savedData[1], null, savedData[2].toInt()) + if (!checkIfContains(place)) { + appendPlace(place) + } + } + } + + fun saveToCache(context: Context) { + val save = JSONArray() + + for (n in places.indices) { + val place = places[n] + if (getSavePermission(place)) { + save.put(n, "${place!!.title}|||||${place.description}|||||${place.id}") + } + } + //save.put("hi|||||sdhsiujdghsiuy|||||45") + + context.saveString("placePreviews", save.toString(), "exploreFragmentCache") + } + + private fun getSavePermission(place: PlacePreview?): Boolean { + if (controlJson == null) { + return true + } + + place?.let { + for (n in 1 until controlJson!!.getLengthOfJsonArray()) { + controlJson!!.getJsonObject(n) + if (place.id == controlJson!!.getAttributeContent("ID").toInt()) { + if (place.title == controlJson!!.getAttributeContentByPath("description/title")) { + val tempPlace = PlacePreview("", controlJson!!.getAttributeContentByPath("description/description_s")) + if (place.description == tempPlace.description) { + return true + } + } + } + } + } + + return false + } + } \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/java/com/example/wikispot/projectScopeVariables.kt b/app/WikiSpot/app/src/main/java/com/example/wikispot/projectScopeVariables.kt index eeacbd6..b0aaf09 100644 --- a/app/WikiSpot/app/src/main/java/com/example/wikispot/projectScopeVariables.kt +++ b/app/WikiSpot/app/src/main/java/com/example/wikispot/projectScopeVariables.kt @@ -18,10 +18,12 @@ object IntentsKeys { object ServerManagement { var serverManager = ServerManager() - const val receiverConnectionOnCheckWait: Long = 20000 + const val receiverConnectionOnCheckWait: Long = 4000 const val viewConnectionOnCheckWait: Long = 5000 const val dataRequestOnAttemptWait: Long = 2000 + const val imageRequestOnAttemptWait: Long = 2000 const val baseUrl = "http://192.168.1.230:8000/" + var selectedServerId = 0 } diff --git a/app/WikiSpot/app/src/main/res/drawable/gradient_fill_for_bottom_nav_bar.xml b/app/WikiSpot/app/src/main/res/drawable/bottom_nav_bar_gradient_background.xml similarity index 55% rename from app/WikiSpot/app/src/main/res/drawable/gradient_fill_for_bottom_nav_bar.xml rename to app/WikiSpot/app/src/main/res/drawable/bottom_nav_bar_gradient_background.xml index fb27ea9..ef95260 100644 --- a/app/WikiSpot/app/src/main/res/drawable/gradient_fill_for_bottom_nav_bar.xml +++ b/app/WikiSpot/app/src/main/res/drawable/bottom_nav_bar_gradient_background.xml @@ -2,9 +2,16 @@ + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/chat_fragment_gradient_background.xml b/app/WikiSpot/app/src/main/res/drawable/chat_fragment_gradient_background.xml new file mode 100644 index 0000000..8812890 --- /dev/null +++ b/app/WikiSpot/app/src/main/res/drawable/chat_fragment_gradient_background.xml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/explore_fragment_gradient_background.xml b/app/WikiSpot/app/src/main/res/drawable/explore_fragment_gradient_background.xml new file mode 100644 index 0000000..dfbabee --- /dev/null +++ b/app/WikiSpot/app/src/main/res/drawable/explore_fragment_gradient_background.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/home_fragment_gradient_background.xml b/app/WikiSpot/app/src/main/res/drawable/home_fragment_gradient_background.xml index c778e7a..674dc97 100644 --- a/app/WikiSpot/app/src/main/res/drawable/home_fragment_gradient_background.xml +++ b/app/WikiSpot/app/src/main/res/drawable/home_fragment_gradient_background.xml @@ -2,8 +2,14 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/WikiSpot/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..6a0151f --- /dev/null +++ b/app/WikiSpot/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/info_fragment_gradient_background.xml b/app/WikiSpot/app/src/main/res/drawable/info_fragment_gradient_background.xml new file mode 100644 index 0000000..a8851c0 --- /dev/null +++ b/app/WikiSpot/app/src/main/res/drawable/info_fragment_gradient_background.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/map_fragment_gradient_background.xml b/app/WikiSpot/app/src/main/res/drawable/map_fragment_gradient_background.xml index 6a9d51b..bb7c2ec 100644 --- a/app/WikiSpot/app/src/main/res/drawable/map_fragment_gradient_background.xml +++ b/app/WikiSpot/app/src/main/res/drawable/map_fragment_gradient_background.xml @@ -3,9 +3,9 @@ android:shape="rectangle"> \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/settings_fragment_gradient_background.xml b/app/WikiSpot/app/src/main/res/drawable/settings_fragment_gradient_background.xml index 0c29434..20337a0 100644 --- a/app/WikiSpot/app/src/main/res/drawable/settings_fragment_gradient_background.xml +++ b/app/WikiSpot/app/src/main/res/drawable/settings_fragment_gradient_background.xml @@ -1,14 +1,12 @@ - + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/drawable/text_background_gradient.xml b/app/WikiSpot/app/src/main/res/drawable/text_background_gradient.xml index a188395..8717005 100644 --- a/app/WikiSpot/app/src/main/res/drawable/text_background_gradient.xml +++ b/app/WikiSpot/app/src/main/res/drawable/text_background_gradient.xml @@ -2,8 +2,8 @@ \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/layout/activity_main.xml b/app/WikiSpot/app/src/main/res/layout/activity_main.xml index ab34a29..f373bb6 100644 --- a/app/WikiSpot/app/src/main/res/layout/activity_main.xml +++ b/app/WikiSpot/app/src/main/res/layout/activity_main.xml @@ -16,7 +16,7 @@ app:layout_constraintStart_toStartOf="parent" app:itemIconTint="@color/bottom_nav_bar_item_color" app:itemTextColor="@color/bottom_nav_bar_item_color" - android:background="@drawable/gradient_fill_for_bottom_nav_bar" + android:background="@drawable/bottom_nav_bar_gradient_background" app:menu="@menu/main_bottom_nav_menu" /> + + + app:layout_constraintTop_toBottomOf="@+id/textView4"> + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/layout/fragment_info.xml b/app/WikiSpot/app/src/main/res/layout/fragment_info.xml new file mode 100644 index 0000000..44c508c --- /dev/null +++ b/app/WikiSpot/app/src/main/res/layout/fragment_info.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cf..7353dbd 100644 --- a/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cf..7353dbd 100644 --- a/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/WikiSpot/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher.png index a571e60..8c6e630 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..1528974 Binary files /dev/null and b/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index 61da551..6f7a1e6 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/WikiSpot/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher.png index c41dd28..f500abb 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..d697cd1 Binary files /dev/null and b/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index db5080a..0f6457a 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/WikiSpot/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 6dba46d..1112784 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..b1921be Binary files /dev/null and b/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index da31a87..c217eef 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/WikiSpot/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 15ac681..0b2aa44 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..1d3038e Binary files /dev/null and b/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index b216f2d..a34b3fc 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/WikiSpot/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index f25a419..e31cc76 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..7d7964b Binary files /dev/null and b/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index e96783c..7e7c423 100644 Binary files a/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/WikiSpot/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/WikiSpot/app/src/main/res/navigation/main_activity_navigation.xml b/app/WikiSpot/app/src/main/res/navigation/main_activity_navigation.xml index 85706f8..323ff8a 100644 --- a/app/WikiSpot/app/src/main/res/navigation/main_activity_navigation.xml +++ b/app/WikiSpot/app/src/main/res/navigation/main_activity_navigation.xml @@ -21,6 +21,9 @@ + + + + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/values-night/themes.xml b/app/WikiSpot/app/src/main/res/values-night/themes.xml deleted file mode 100644 index ffd7ee6..0000000 --- a/app/WikiSpot/app/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/values/attrs.xml b/app/WikiSpot/app/src/main/res/values/attrs.xml index 095c445..f990a29 100644 --- a/app/WikiSpot/app/src/main/res/values/attrs.xml +++ b/app/WikiSpot/app/src/main/res/values/attrs.xml @@ -1,12 +1,37 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/WikiSpot/app/src/main/res/values/colors.xml b/app/WikiSpot/app/src/main/res/values/colors.xml index f1df13c..31ffbb5 100644 --- a/app/WikiSpot/app/src/main/res/values/colors.xml +++ b/app/WikiSpot/app/src/main/res/values/colors.xml @@ -8,48 +8,45 @@ #FF000000 #FFFFFFFF - - - #E10A1C2F - #142448 - #DC17294D - #10132F - #CE131C33 + #ECD21A1A + #320747 #33C4BCC9 #EC000000 + #80E5BEFF + #80FFB5F0 + + #FCDD94 + #C5F8AB + + #FCB0EF + #9ECFFF + #9FE7FF + + #A1DEFC + #A5CBFF + #F9B6F6 + + #83E1FF + #9EC6FF + #FEBBFF + + #FBBEFC + #A5CBFF + #95DDFC + + #92EB97FC + #A198F9 + #74C7F7 + + #FFB6FB + #A7D2FF + #96E7FF + - - #422DA9 - #5829B1 - #6A1B9A - #AD1457 - #C62845 #FFB571 + #320747 #33222222 #4527A0 diff --git a/app/WikiSpot/app/src/main/res/values/ic_launcher_background.xml b/app/WikiSpot/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..06ea7bf --- /dev/null +++ b/app/WikiSpot/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #84ABFC + \ No newline at end of file diff --git a/app/WikiSpot/app/src/main/res/values/themes.xml b/app/WikiSpot/app/src/main/res/values/themes.xml index 814b5fb..4168bf6 100644 --- a/app/WikiSpot/app/src/main/res/values/themes.xml +++ b/app/WikiSpot/app/src/main/res/values/themes.xml @@ -12,20 +12,45 @@ #F48FB1 @color/black - - @color/chatFragmentBackground - @color/exploreFragmentBackground - @color/homeFragmentBackground - @color/mapFragmentBackground - @color/settingsFragmentBackground + + + @color/textBackgroundGradientStartColor + @color/textBackgroundGradientEndColor + + @color/bottomNavBarGradientStartColor + @color/bottomNavBarGradientEndColor + + @color/chatFragmentGradientStartColor + @color/chatFragmentGradientCenterColor + @color/chatFragmentGradientEndColor + + @color/exploreFragmentGradientStartColor + @color/exploreFragmentGradientCenterColor + @color/exploreFragmentGradientEndColor + + @color/homeFragmentGradientStartColor + @color/homeFragmentGradientCenterColor + @color/homeFragmentGradientEndColor + + @color/mapFragmentGradientStartColor + @color/mapFragmentGradientCenterColor + @color/mapFragmentGradientEndColor + + @color/settingsFragmentGradientStartColor + @color/settingsFragmentGradientCenterColor + @color/settingsFragmentGradientEndColor + + @color/infoFragmentGradientStartColor + @color/infoFragmentGradientCenterColor + @color/infoFragmentGradientEndColor @color/bottomNavBarCheckedItemColor @color/bottomNavBarRippleColor - @style/Widget.App.BottomNavigationView + @color/statusBarColor @@ -34,14 +59,7 @@ @@ -56,20 +74,45 @@ @color/teal_200 @color/black - - @color/chatFragmentBackgroundDark - @color/exploreFragmentBackgroundDark - @color/homeFragmentBackgroundDark - @color/mapFragmentBackgroundDark - @color/settingsFragmentBackgroundDark + - + @color/textBackgroundGradientStartColor + @color/textBackgroundGradientEndColor + + @color/bottomNavBarGradientStartColor + @color/bottomNavBarGradientEndColor + + @color/chatFragmentGradientStartColor + @color/chatFragmentGradientCenterColor + @color/chatFragmentGradientEndColor + + @color/exploreFragmentGradientStartColor + @color/exploreFragmentGradientCenterColor + @color/exploreFragmentGradientEndColor + + @color/homeFragmentGradientStartColor + @color/homeFragmentGradientCenterColor + @color/homeFragmentGradientEndColor + + @color/mapFragmentGradientStartColor + @color/mapFragmentGradientCenterColor + @color/mapFragmentGradientEndColor + + @color/settingsFragmentGradientStartColor + @color/settingsFragmentGradientCenterColor + @color/settingsFragmentGradientEndColor + + @color/infoFragmentGradientStartColor + @color/infoFragmentGradientCenterColor + @color/infoFragmentGradientEndColor + + @color/bottomNavBarCheckedItemColorDark @color/bottomNavBarRippleColorDark - @style/Widget.App.BottomNavigationViewDark + @color/statusBarColorDark @@ -79,7 +122,6 @@ \ No newline at end of file diff --git a/app/WikiSpot/build.gradle b/app/WikiSpot/build.gradle index 49ea6fa..6673cc9 100644 --- a/app/WikiSpot/build.gradle +++ b/app/WikiSpot/build.gradle @@ -4,6 +4,7 @@ buildscript { repositories { google() jcenter() + mavenCentral() } dependencies { classpath "com.android.tools.build:gradle:4.1.1"