From 07bd526681272b2736aa3956c1c2e5b1d09f3222 Mon Sep 17 00:00:00 2001 From: Gideon Okuro Date: Thu, 5 Dec 2024 15:54:15 +0300 Subject: [PATCH 1/7] attempt to view html --- .../ole/planet/myplanet/model/RealmMyLibrary.kt | 14 ++++++++++++++ .../myplanet/service/UploadToShelfService.kt | 2 +- .../planet/myplanet/ui/viewer/WebViewActivity.kt | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt b/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt index b360c194d3..6b4932a791 100644 --- a/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt +++ b/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt @@ -2,6 +2,7 @@ package org.ole.planet.myplanet.model import android.content.Context import android.content.SharedPreferences +import android.util.Log import com.google.gson.JsonArray import com.google.gson.JsonNull import com.google.gson.JsonObject @@ -258,6 +259,7 @@ open class RealmMyLibrary : RealmObject() { if (!mRealm.isInTransaction) { mRealm.beginTransaction() } + logLargeString("insertMyLibrary", doc.toString()) val resourceId = JsonUtils.getString("_id", doc) val settings = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) var resource = mRealm.where(RealmMyLibrary::class.java).equalTo("id", resourceId).findFirst() @@ -265,6 +267,7 @@ open class RealmMyLibrary : RealmObject() { resource = mRealm.createObject(RealmMyLibrary::class.java, resourceId) } resource?.apply { + setUserId(userId) _id = resourceId if (!stepId.isNullOrBlank()) { @@ -311,6 +314,8 @@ open class RealmMyLibrary : RealmObject() { isPrivate = JsonUtils.getBoolean("private", doc) setLanguages(JsonUtils.getJsonArray("languages", doc), this) } + + logLargeString("insertMyLibrary resource", resource.id.toString() + " " + resource.resourceRemoteAddress) mRealm.commitTransaction() val csvRow = arrayOf( @@ -409,5 +414,14 @@ open class RealmMyLibrary : RealmObject() { fun getSubjects(libraries: List): Set { return libraries.flatMap { it.subject ?: emptyList() }.toSet() } + + fun logLargeString(tag: String, content: String) { + if (content.length > 3000) { + Log.d(tag, content.substring(0, 3000)) + logLargeString(tag, content.substring(3000)) + } else { + Log.d(tag, content) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/org/ole/planet/myplanet/service/UploadToShelfService.kt b/app/src/main/java/org/ole/planet/myplanet/service/UploadToShelfService.kt index 652c0e1531..d944ccf5aa 100644 --- a/app/src/main/java/org/ole/planet/myplanet/service/UploadToShelfService.kt +++ b/app/src/main/java/org/ole/planet/myplanet/service/UploadToShelfService.kt @@ -43,7 +43,7 @@ class UploadToShelfService(context: Context) { for (model in userModels) { try { val password = sharedPreferences.getString("loginUserPassword", "") - val header = "Basic " + Base64.encodeToString(("${model.name}:${password}").toByteArray(), Base64.NO_WRAP) + val header = "Basic ${Base64.encodeToString(("${ model.name }:${ password }").toByteArray(), Base64.NO_WRAP)}" val res = apiInterface?.getJsonObject(header, "${replacedUrl(model)}/_users/org.couchdb.user:${model.name}")?.execute() if (res?.body() == null) { val obj = model.serialize() diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt index 7dfbefc064..d88a6d1b87 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt @@ -4,6 +4,7 @@ import android.graphics.Bitmap import android.net.Uri import android.os.Bundle import android.text.TextUtils +import android.util.Log import android.view.View import android.webkit.CookieManager import android.webkit.WebChromeClient @@ -25,6 +26,7 @@ class WebViewActivity : AppCompatActivity() { fromDeepLink = !TextUtils.isEmpty(dataFromDeepLink) val title: String? = intent.getStringExtra("title") link = intent.getStringExtra("link") ?: "" + Log.d("WebViewActivity", "onCreate: $link") clearCookie() if (!TextUtils.isEmpty(title)) { activityWebViewBinding.contentWebView.webTitle.text = title From fe4fddc8f44ca990c46e3f5d32fb73959e9fabe1 Mon Sep 17 00:00:00 2001 From: Gideon Okuro Date: Thu, 5 Dec 2024 16:11:43 +0300 Subject: [PATCH 2/7] second attempt --- .../myplanet/ui/viewer/WebViewActivity.kt | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt index d88a6d1b87..01af74e9b1 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt @@ -8,10 +8,12 @@ import android.util.Log import android.view.View import android.webkit.CookieManager import android.webkit.WebChromeClient +import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient import androidx.appcompat.app.AppCompatActivity import org.ole.planet.myplanet.databinding.ActivityWebViewBinding +import org.ole.planet.myplanet.utilities.Utilities class WebViewActivity : AppCompatActivity() { private lateinit var activityWebViewBinding: ActivityWebViewBinding @@ -34,13 +36,25 @@ class WebViewActivity : AppCompatActivity() { activityWebViewBinding.contentWebView.pBar.max = 100 activityWebViewBinding.contentWebView.pBar.progress = 0 setListeners() - activityWebViewBinding.contentWebView.wv.settings.javaScriptEnabled = true - activityWebViewBinding.contentWebView.wv.settings.javaScriptCanOpenWindowsAutomatically = true - activityWebViewBinding.contentWebView.wv.loadUrl(link) + activityWebViewBinding.contentWebView.wv.settings.apply { + javaScriptEnabled = true + domStorageEnabled = true + javaScriptCanOpenWindowsAutomatically = true + mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + setSupportZoom(true) + builtInZoomControls = true + } + + val headers = mapOf("Authorization" to Utilities.header) + +// activityWebViewBinding.contentWebView.wv.settings.javaScriptEnabled = true +// activityWebViewBinding.contentWebView.wv.settings.javaScriptCanOpenWindowsAutomatically = true + activityWebViewBinding.contentWebView.wv.loadUrl(link, headers) activityWebViewBinding.contentWebView.finish.setOnClickListener { finish() } setWebClient() } + private fun setWebClient() { activityWebViewBinding.contentWebView.wv.webViewClient = object : WebViewClient() { override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { @@ -64,7 +78,6 @@ class WebViewActivity : AppCompatActivity() { cookieManager.flush() } - private fun setListeners() { activityWebViewBinding.contentWebView.wv.webChromeClient = object : WebChromeClient() { override fun onProgressChanged(view: WebView, newProgress: Int) { @@ -84,4 +97,5 @@ class WebViewActivity : AppCompatActivity() { } } } + } From 8a6737dd5d5ed92d7ba4245417a9ba6159da21fd Mon Sep 17 00:00:00 2001 From: Gideon Okuro Date: Fri, 6 Dec 2024 16:28:49 +0300 Subject: [PATCH 3/7] successfully save html --- .../myplanet/base/BaseContainerFragment.kt | 56 ++++++++++++++-- .../planet/myplanet/model/RealmMyLibrary.kt | 36 +++++++++- .../myplanet/ui/resources/AdapterResource.kt | 67 ++++++++++++++++--- .../myplanet/ui/viewer/WebViewActivity.kt | 23 +++++-- 4 files changed, 162 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt index 83545b2d85..0cc672bd5b 100644 --- a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt +++ b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt @@ -8,6 +8,7 @@ import android.net.Uri import android.os.Bundle import android.provider.Settings import android.text.TextUtils +import android.util.Log import android.view.LayoutInflater import android.view.MotionEvent import android.view.View @@ -72,9 +73,8 @@ abstract class BaseContainerFragment : BaseResourceFragment() { AdapterCourses.showRating(`object`, rating, timesRated, ratingBar) } } - fun getUrlsAndStartDownload( - lib: List, urls: ArrayList - ) { + + fun getUrlsAndStartDownload(lib: List, urls: ArrayList) { for (library in lib) { val url = Utilities.getUrl(library) if (!FileUtils.checkFileExist(url) && !TextUtils.isEmpty(url)) urls.add(url) @@ -83,6 +83,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { activity, getString(R.string.no_images_to_download) ) } + fun initRatingView(type: String?, id: String?, title: String?, listener: OnRatingChangeListener?) { timesRated = requireView().findViewById(R.id.times_rated) rating = requireView().findViewById(R.id.tv_rating) @@ -102,12 +103,14 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } } } + override fun onAttach(context: Context) { super.onAttach(context) if (context is OnHomeItemClickListener) { homeItemClickListener = context } } + private fun openIntent(items: RealmMyLibrary, typeClass: Class<*>?) { val fileOpenIntent = Intent(activity, typeClass) if (items.resourceLocalAddress?.contains("ole/audio") == true || items.resourceLocalAddress?.contains("ole/video") == true) { @@ -119,6 +122,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } startActivity(fileOpenIntent) } + private fun openPdf(item: RealmMyLibrary) { val fileOpenIntent = Intent(activity, PDFReaderActivity::class.java) fileOpenIntent.putExtra("TOUCHED_FILE", item.id + "/" + item.resourceLocalAddress) @@ -149,10 +153,16 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } private fun checkFileExtension(items: RealmMyLibrary) { - val filenameArray = items.resourceLocalAddress?.split("\\.".toRegex())?.toTypedArray() - val extension = filenameArray?.get(filenameArray.size - 1) +// val filenameArray = items.resourceLocalAddress?.split("\\.".toRegex())?.toTypedArray() +// val extension = filenameArray?.get(filenameArray.size - 1) val mimetype = Utilities.getMimeType(items.resourceLocalAddress) val userId = "${model?.id}" + Log.d("FileExtension", "Mimetype: ${items.resourceLocalAddress}") + + val extension = items.resourceLocalAddress + ?.substringAfterLast('.', "") + ?.lowercase() + val existingAction = mRealm.where(RealmUserChallengeActions::class.java) .equalTo("userId", userId) @@ -195,12 +205,31 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } openIntent(items, TextFileViewerActivity::class.java) } + "html", "htm" -> { + if (existingAction == null) { + createAction(mRealm, userId, items.resourceId, "resourceOpen") + } + openHtmlResource(items) + } "md" -> { + // Special handling for README.md + if (items.resourceLocalAddress?.contains("README.md", ignoreCase = true) == true) { + // Optionally log or handle README.md differently + Log.d("FileExtension", "Detected README.md file") + return // Or handle it specifically + } + if (existingAction == null) { createAction(mRealm, userId, items.resourceId, "resourceOpen") } openIntent(items, MarkdownViewerActivity::class.java) } +// "md" -> { +// if (existingAction == null) { +// createAction(mRealm, userId, items.resourceId, "resourceOpen") +// } +// openIntent(items, MarkdownViewerActivity::class.java) +// } "csv" -> { if (existingAction == null) { createAction(mRealm, userId, items.resourceId, "resourceOpen") @@ -213,6 +242,12 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } installApk(items) } +// "html", "htm" -> { +// if (existingAction == null) { +// createAction(mRealm, userId, items.resourceId, "resourceOpen") +// } +// openHtmlResource(items) +// } else -> Toast.makeText(activity, getString(R.string.this_file_type_is_currently_unsupported), Toast.LENGTH_LONG).show() } } @@ -270,6 +305,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { checkFileExtension(items) } } + open fun playVideo(videoType: String, items: RealmMyLibrary) { val intent = Intent(activity, VideoPlayerActivity::class.java) val bundle = Bundle() @@ -333,6 +369,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } } } + fun setResourceButton(resources: List?, btnResources: Button) { if (resources.isNullOrEmpty()) { btnResources.visibility = View.GONE @@ -347,6 +384,15 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } } + private fun openHtmlResource(items: RealmMyLibrary) { + val intent = Intent(activity, WebViewActivity::class.java).apply { + putExtra("TOUCHED_FILE", "${items.id}/${items.resourceLocalAddress}") + putExtra("title", items.title) + putExtra("isLocalFile", true) + } + startActivity(intent) + } + open fun handleBackPressed() { val fragmentManager = parentFragmentManager fragmentManager.popBackStack() diff --git a/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt b/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt index 6b4932a791..55b5f1b7d6 100644 --- a/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt +++ b/app/src/main/java/org/ole/planet/myplanet/model/RealmMyLibrary.kt @@ -21,6 +21,7 @@ import java.io.FileWriter import java.io.IOException import java.util.Calendar import java.util.Date +import java.util.UUID open class RealmMyLibrary : RealmObject() { @PrimaryKey @@ -64,6 +65,8 @@ open class RealmMyLibrary : RealmObject() { var courseId: String? = null var stepId: String? = null var isPrivate: Boolean = false + var attachments: RealmList? = null + fun serializeResource(): JsonObject { return JsonObject().apply { addProperty("_id", _id) @@ -282,7 +285,25 @@ open class RealmMyLibrary : RealmObject() { description = JsonUtils.getString("description", doc) if (doc.has("_attachments")) { val attachments = doc["_attachments"].asJsonObject - attachments.entrySet().forEach { (key, _) -> + if (this.attachments == null) { + this.attachments = RealmList() + } + + attachments.entrySet().forEach { (key, attachmentValue) -> + val attachmentObj = attachmentValue.asJsonObject + + val realmAttachment = mRealm.createObject(RealmAttachment::class.java, UUID.randomUUID().toString()) + realmAttachment.apply { + name = key + contentType = attachmentObj.get("content_type")?.asString + length = attachmentObj.get("length")?.asLong ?: 0 + digest = attachmentObj.get("digest")?.asString + isStub = attachmentObj.get("stub")?.asBoolean == true + revpos = attachmentObj.get("revpos")?.asInt ?: 0 + } + + this.attachments?.add(realmAttachment) + if (key.indexOf("/") < 0) { resourceRemoteAddress = "${settings.getString("couchdbURL", "http://")}/resources/$resourceId/$key" resourceLocalAddress = key @@ -407,7 +428,7 @@ open class RealmMyLibrary : RealmObject() { @JvmStatic fun getArrayList(libraries: List, type: String): Set { - return libraries.mapNotNull { if (type == "mediums") it.mediaType else it.language }.filterNot { it.isNullOrBlank() }.toSet() + return libraries.mapNotNull { if (type == "mediums") it.mediaType else it.language }.filterNot { it.isBlank() }.toSet() } @JvmStatic @@ -424,4 +445,15 @@ open class RealmMyLibrary : RealmObject() { } } } +} + +open class RealmAttachment : RealmObject() { + @PrimaryKey + var id: String? = null + var name: String? = null + var contentType: String? = null + var length: Long = 0 + var digest: String? = null + var isStub: Boolean = false + var revpos: Int = 0 } \ No newline at end of file diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/resources/AdapterResource.kt b/app/src/main/java/org/ole/planet/myplanet/ui/resources/AdapterResource.kt index a259a71a4a..ff523d7846 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/resources/AdapterResource.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/resources/AdapterResource.kt @@ -2,6 +2,7 @@ package org.ole.planet.myplanet.ui.resources import android.content.Context import android.text.TextUtils +import android.util.Log import android.view.LayoutInflater import android.view.MotionEvent import android.view.View @@ -19,6 +20,7 @@ import org.ole.planet.myplanet.callback.OnLibraryItemSelected import org.ole.planet.myplanet.callback.OnRatingChangeListener import org.ole.planet.myplanet.databinding.RowLibraryBinding import org.ole.planet.myplanet.model.RealmMyLibrary +import org.ole.planet.myplanet.model.RealmMyLibrary.Companion.logLargeString import org.ole.planet.myplanet.model.RealmTag import org.ole.planet.myplanet.model.RealmUserModel import org.ole.planet.myplanet.service.UserProfileDbHandler @@ -83,19 +85,67 @@ class AdapterResource(private val context: Context, private var libraryList: Lis } holder.rowLibraryBinding.tvDate.text = libraryList[position]?.createdDate?.let { formatDate(it, "MMM dd, yyyy") } displayTagCloud(holder.rowLibraryBinding.flexboxDrawable, position) - holder.itemView.setOnClickListener { openLibrary(libraryList[position]) } + holder.itemView.setOnClickListener { + openLibrary(libraryList[position]) + val libraryItem = realm.where(RealmMyLibrary::class.java) + .equalTo("id", libraryList[position]?.id) + .findFirst() + Log.d("AdapterResource", "onBindViewHolder: $libraryItem") + libraryItem?.let { item -> + val allDetails = """ + _id: ${item._id} + _rev: ${item._rev} + Title: ${item.title} + Author: ${item.author} + Year: ${item.year} + Description: ${item.description} + Language: ${item.language} + Publisher: ${item.publisher} + Link to License: ${item.linkToLicense} + Subjects: ${item.subject?.joinToString()} + Levels: ${item.level?.joinToString()} + Resource Type: ${item.resourceType} + Open With: ${item.openWith} + Media Type: ${item.mediaType} + Article Date: ${item.articleDate} + Resource For: ${item.resourceFor?.joinToString()} + Added By: ${item.addedBy} + Upload Date: ${item.uploadDate} + Created Date: ${item.createdDate} + Resource Remote Address: ${item.resourceRemoteAddress} + Resource Local Address: ${item.resourceLocalAddress} + Resource Offline: ${item.resourceOffline} + Resource ID: ${item.resourceId} + Downloaded Rev: ${item.downloadedRev} + Needs Optimization: ${item.needsOptimization} + Tags: ${item.tag?.joinToString()} + Languages: ${item.languages?.joinToString()} + Course ID: ${item.courseId} + Step ID: ${item.stepId} + Is Private: ${item.isPrivate} + User ID: ${item.userId?.joinToString()} + Filename: ${item.filename} + Translations Audio Path: ${item.translationAudioPath} + Average Rating: ${item.averageRating} + Times Rated: ${item.timesRated} + Sum: ${item.sum} + attachment: ${item.attachments?.joinToString()} + """.trimIndent() + + logLargeString("AdapterResource", "Full Library Item Details:\n$allDetails") + } + } userModel = UserProfileDbHandler(context).userModel if (libraryList[position]?.isResourceOffline() == true) { holder.rowLibraryBinding.ivDownloaded.visibility = View.INVISIBLE } else { holder.rowLibraryBinding.ivDownloaded.visibility = View.VISIBLE } - holder.rowLibraryBinding.ivDownloaded.contentDescription = - if (libraryList[position]?.isResourceOffline() == true) { - context.getString(R.string.view) - } else { - context.getString(R.string.download) - } + holder.rowLibraryBinding.ivDownloaded.contentDescription = if (libraryList[position]?.isResourceOffline() == true) { + context.getString(R.string.view) + } else { + context.getString(R.string.download) + } if (ratingMap.containsKey(libraryList[position]?.resourceId)) { val `object` = ratingMap[libraryList[position]?.resourceId] AdapterCourses.showRating(`object`, holder.rowLibraryBinding.rating, holder.rowLibraryBinding.timesRated, holder.rowLibraryBinding.ratingBar) @@ -105,8 +155,7 @@ class AdapterResource(private val context: Context, private var libraryList: Lis if (userModel?.isGuest() == false) { holder.rowLibraryBinding.checkbox.setOnClickListener { view: View -> - holder.rowLibraryBinding.checkbox.contentDescription = - context.getString(R.string.select_res_course, libraryList[position]?.title) + holder.rowLibraryBinding.checkbox.contentDescription = context.getString(R.string.select_res_course, libraryList[position]?.title) Utilities.handleCheck((view as CheckBox).isChecked, position, selectedItems, libraryList) if (listener != null) listener?.onSelectedListChange(selectedItems) } diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt index 01af74e9b1..a847dda0de 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt @@ -12,13 +12,16 @@ import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient import androidx.appcompat.app.AppCompatActivity +import org.ole.planet.myplanet.MainApplication import org.ole.planet.myplanet.databinding.ActivityWebViewBinding import org.ole.planet.myplanet.utilities.Utilities +import java.io.File class WebViewActivity : AppCompatActivity() { private lateinit var activityWebViewBinding: ActivityWebViewBinding private var fromDeepLink = false private lateinit var link: String + private var isLocalFile = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -28,11 +31,15 @@ class WebViewActivity : AppCompatActivity() { fromDeepLink = !TextUtils.isEmpty(dataFromDeepLink) val title: String? = intent.getStringExtra("title") link = intent.getStringExtra("link") ?: "" - Log.d("WebViewActivity", "onCreate: $link") + isLocalFile = intent.getBooleanExtra("isLocalFile", false) + + Log.d("WebViewActivity", "onCreate: $link, isLocalFile: $isLocalFile") clearCookie() + if (!TextUtils.isEmpty(title)) { activityWebViewBinding.contentWebView.webTitle.text = title } + activityWebViewBinding.contentWebView.pBar.max = 100 activityWebViewBinding.contentWebView.pBar.progress = 0 setListeners() @@ -45,11 +52,19 @@ class WebViewActivity : AppCompatActivity() { builtInZoomControls = true } - val headers = mapOf("Authorization" to Utilities.header) - // activityWebViewBinding.contentWebView.wv.settings.javaScriptEnabled = true // activityWebViewBinding.contentWebView.wv.settings.javaScriptCanOpenWindowsAutomatically = true - activityWebViewBinding.contentWebView.wv.loadUrl(link, headers) + if (isLocalFile) { + val touchedFile = intent.getStringExtra("TOUCHED_FILE") + if (!touchedFile.isNullOrEmpty()) { + val localFilePath = File(MainApplication.context.getExternalFilesDir(null), touchedFile).absolutePath + activityWebViewBinding.contentWebView.wv.loadUrl("file://$localFilePath") + } + } else { + // Existing remote URL loading logic + val headers = mapOf("Authorization" to Utilities.header) + activityWebViewBinding.contentWebView.wv.loadUrl(link, headers) + } activityWebViewBinding.contentWebView.finish.setOnClickListener { finish() } setWebClient() } From 466ed454bff6cd1a2abb0afbb546fae75cfde26c Mon Sep 17 00:00:00 2001 From: Gideon Okuro Date: Fri, 6 Dec 2024 16:35:22 +0300 Subject: [PATCH 4/7] match lite file --- .../myplanet/base/BaseContainerFragment.kt | 19 +-------- .../base/BaseContainerFragment.kt.lite | 41 ++++++++++++++++--- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt index 0cc672bd5b..9514ddd210 100644 --- a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt +++ b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt @@ -153,8 +153,6 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } private fun checkFileExtension(items: RealmMyLibrary) { -// val filenameArray = items.resourceLocalAddress?.split("\\.".toRegex())?.toTypedArray() -// val extension = filenameArray?.get(filenameArray.size - 1) val mimetype = Utilities.getMimeType(items.resourceLocalAddress) val userId = "${model?.id}" Log.d("FileExtension", "Mimetype: ${items.resourceLocalAddress}") @@ -163,7 +161,6 @@ abstract class BaseContainerFragment : BaseResourceFragment() { ?.substringAfterLast('.', "") ?.lowercase() - val existingAction = mRealm.where(RealmUserChallengeActions::class.java) .equalTo("userId", userId) .equalTo("resourceId", items.resourceId) @@ -212,11 +209,9 @@ abstract class BaseContainerFragment : BaseResourceFragment() { openHtmlResource(items) } "md" -> { - // Special handling for README.md if (items.resourceLocalAddress?.contains("README.md", ignoreCase = true) == true) { - // Optionally log or handle README.md differently Log.d("FileExtension", "Detected README.md file") - return // Or handle it specifically + return } if (existingAction == null) { @@ -224,12 +219,6 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } openIntent(items, MarkdownViewerActivity::class.java) } -// "md" -> { -// if (existingAction == null) { -// createAction(mRealm, userId, items.resourceId, "resourceOpen") -// } -// openIntent(items, MarkdownViewerActivity::class.java) -// } "csv" -> { if (existingAction == null) { createAction(mRealm, userId, items.resourceId, "resourceOpen") @@ -242,12 +231,6 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } installApk(items) } -// "html", "htm" -> { -// if (existingAction == null) { -// createAction(mRealm, userId, items.resourceId, "resourceOpen") -// } -// openHtmlResource(items) -// } else -> Toast.makeText(activity, getString(R.string.this_file_type_is_currently_unsupported), Toast.LENGTH_LONG).show() } } diff --git a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite index 8a64f08109..d84ae4ad00 100644 --- a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite +++ b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite @@ -8,6 +8,7 @@ import android.net.Uri import android.os.Bundle //import android.provider.Settings import android.text.TextUtils +import android.util.Log import android.view.LayoutInflater import android.view.MotionEvent import android.view.View @@ -72,9 +73,8 @@ abstract class BaseContainerFragment : BaseResourceFragment() { AdapterCourses.showRating(`object`, rating, timesRated, ratingBar) } } - fun getUrlsAndStartDownload( - lib: List, urls: ArrayList - ) { + + fun getUrlsAndStartDownload(lib: List, urls: ArrayList) { for (library in lib) { val url = Utilities.getUrl(library) if (!FileUtils.checkFileExist(url) && !TextUtils.isEmpty(url)) urls.add(url) @@ -83,6 +83,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { activity, getString(R.string.no_images_to_download) ) } + fun initRatingView(type: String?, id: String?, title: String?, listener: OnRatingChangeListener?) { timesRated = requireView().findViewById(R.id.times_rated) rating = requireView().findViewById(R.id.tv_rating) @@ -102,12 +103,14 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } } } + override fun onAttach(context: Context) { super.onAttach(context) if (context is OnHomeItemClickListener) { homeItemClickListener = context } } + private fun openIntent(items: RealmMyLibrary, typeClass: Class<*>?) { val fileOpenIntent = Intent(activity, typeClass) if (items.resourceLocalAddress?.contains("ole/audio") == true || items.resourceLocalAddress?.contains("ole/video") == true) { @@ -119,6 +122,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } startActivity(fileOpenIntent) } + private fun openPdf(item: RealmMyLibrary) { val fileOpenIntent = Intent(activity, PDFReaderActivity::class.java) fileOpenIntent.putExtra("TOUCHED_FILE", item.id + "/" + item.resourceLocalAddress) @@ -149,10 +153,13 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } private fun checkFileExtension(items: RealmMyLibrary) { - val filenameArray = items.resourceLocalAddress?.split("\\.".toRegex())?.toTypedArray() - val extension = filenameArray?.get(filenameArray.size - 1) val mimetype = Utilities.getMimeType(items.resourceLocalAddress) val userId = "${model?.id}" + Log.d("FileExtension", "Mimetype: ${items.resourceLocalAddress}") + + val extension = items.resourceLocalAddress + ?.substringAfterLast('.', "") + ?.lowercase() val existingAction = mRealm.where(RealmUserChallengeActions::class.java) .equalTo("userId", userId) @@ -195,7 +202,20 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } openIntent(items, TextFileViewerActivity::class.java) } + "html", "htm" -> { + if (existingAction == null) { + createAction(mRealm, userId, items.resourceId, "resourceOpen") + } + openHtmlResource(items) + } "md" -> { + // Special handling for README.md + if (items.resourceLocalAddress?.contains("README.md", ignoreCase = true) == true) { + // Optionally log or handle README.md differently + Log.d("FileExtension", "Detected README.md file") + return // Or handle it specifically + } + if (existingAction == null) { createAction(mRealm, userId, items.resourceId, "resourceOpen") } @@ -270,6 +290,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { checkFileExtension(items) } } + open fun playVideo(videoType: String, items: RealmMyLibrary) { val intent = Intent(activity, VideoPlayerActivity::class.java) val bundle = Bundle() @@ -333,6 +354,7 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } } } + fun setResourceButton(resources: List?, btnResources: Button) { if (resources.isNullOrEmpty()) { btnResources.visibility = View.GONE @@ -347,6 +369,15 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } } + private fun openHtmlResource(items: RealmMyLibrary) { + val intent = Intent(activity, WebViewActivity::class.java).apply { + putExtra("TOUCHED_FILE", "${items.id}/${items.resourceLocalAddress}") + putExtra("title", items.title) + putExtra("isLocalFile", true) + } + startActivity(intent) + } + // open fun handleBackPressed() { // val fragmentManager = parentFragmentManager // fragmentManager.popBackStack() From 88701bbd87550884e565f4a416494a141edb37aa Mon Sep 17 00:00:00 2001 From: Gideon Okuro Date: Fri, 6 Dec 2024 16:37:55 +0300 Subject: [PATCH 5/7] match lite file --- .../ole/planet/myplanet/base/BaseContainerFragment.kt.lite | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite index d84ae4ad00..a127e39f4d 100644 --- a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite +++ b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt.lite @@ -209,11 +209,9 @@ abstract class BaseContainerFragment : BaseResourceFragment() { openHtmlResource(items) } "md" -> { - // Special handling for README.md if (items.resourceLocalAddress?.contains("README.md", ignoreCase = true) == true) { - // Optionally log or handle README.md differently Log.d("FileExtension", "Detected README.md file") - return // Or handle it specifically + return } if (existingAction == null) { From f15cde9181934225d4a916c2ed4fb7b3c52733d9 Mon Sep 17 00:00:00 2001 From: Gideon Okuro Date: Tue, 10 Dec 2024 18:32:47 +0300 Subject: [PATCH 6/7] html games still not able to view --- .../myplanet/base/BaseContainerFragment.kt | 41 +- .../myplanet/ui/viewer/WebViewActivity.kt | 450 +++++++++++++++++- app/src/main/res/xml/file_paths.xml | 1 + 3 files changed, 456 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt index 9514ddd210..ce5b816888 100644 --- a/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt +++ b/app/src/main/java/org/ole/planet/myplanet/base/BaseContainerFragment.kt @@ -131,25 +131,30 @@ abstract class BaseContainerFragment : BaseResourceFragment() { } fun openResource(items: RealmMyLibrary) { - val matchingItems = mRealm.where(RealmMyLibrary::class.java) - .equalTo("resourceLocalAddress", items.resourceLocalAddress) - .findAll() - val anyOffline = matchingItems.any { it.isResourceOffline() } - if (anyOffline) { - val offlineItem = matchingItems.first { it.isResourceOffline()} - openFileType(offlineItem, "offline") - } else { - if (items.isResourceOffline()) { - openFileType(items, "offline") - } else if (FileUtils.getFileExtension(items.resourceLocalAddress) == "mp4") { - openFileType(items, "online") - } else { - val arrayList = ArrayList() - arrayList.add(Utilities.getUrl(items)) - startDownload(arrayList) - profileDbHandler.setResourceOpenCount(items, KEY_RESOURCE_DOWNLOAD) - } + val intent = Intent(context, WebViewActivity::class.java).apply { + putExtra("isLocalFile", true) + putExtra("RESOURCE_ID", "6f7b1d7a7c9c73e736b38657bc013556") // The _id from the library item } + startActivity(intent) +// val matchingItems = mRealm.where(RealmMyLibrary::class.java) +// .equalTo("resourceLocalAddress", items.resourceLocalAddress) +// .findAll() +// val anyOffline = matchingItems.any { it.isResourceOffline() } +// if (anyOffline) { +// val offlineItem = matchingItems.first { it.isResourceOffline()} +// openFileType(offlineItem, "offline") +// } else { +// if (items.isResourceOffline()) { +// openFileType(items, "offline") +// } else if (FileUtils.getFileExtension(items.resourceLocalAddress) == "mp4") { +// openFileType(items, "online") +// } else { +// val arrayList = ArrayList() +// arrayList.add(Utilities.getUrl(items)) +// startDownload(arrayList) +// profileDbHandler.setResourceOpenCount(items, KEY_RESOURCE_DOWNLOAD) +// } +// } } private fun checkFileExtension(items: RealmMyLibrary) { diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt index a847dda0de..00211064e7 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt @@ -1,27 +1,42 @@ package org.ole.planet.myplanet.ui.viewer +import android.annotation.TargetApi import android.graphics.Bitmap import android.net.Uri +import android.os.Build import android.os.Bundle import android.text.TextUtils import android.util.Log import android.view.View import android.webkit.CookieManager import android.webkit.WebChromeClient +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.FileProvider +import androidx.lifecycle.lifecycleScope +import io.realm.Realm +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.ole.planet.myplanet.MainApplication import org.ole.planet.myplanet.databinding.ActivityWebViewBinding +import org.ole.planet.myplanet.model.RealmAttachment +import org.ole.planet.myplanet.model.RealmMyLibrary import org.ole.planet.myplanet.utilities.Utilities import java.io.File +import java.net.HttpURLConnection +import java.net.URL class WebViewActivity : AppCompatActivity() { private lateinit var activityWebViewBinding: ActivityWebViewBinding private var fromDeepLink = false private lateinit var link: String private var isLocalFile = false + var resourceId: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -33,6 +48,16 @@ class WebViewActivity : AppCompatActivity() { link = intent.getStringExtra("link") ?: "" isLocalFile = intent.getBooleanExtra("isLocalFile", false) + if (isLocalFile) { + resourceId = intent.getStringExtra("RESOURCE_ID") + Log.d("okuro", "$resourceId") + if (!resourceId.isNullOrEmpty()) { + lifecycleScope.launch { + loadLocalHtmlResource(resourceId) + } + } + } + Log.d("WebViewActivity", "onCreate: $link, isLocalFile: $isLocalFile") clearCookie() @@ -52,26 +77,420 @@ class WebViewActivity : AppCompatActivity() { builtInZoomControls = true } -// activityWebViewBinding.contentWebView.wv.settings.javaScriptEnabled = true -// activityWebViewBinding.contentWebView.wv.settings.javaScriptCanOpenWindowsAutomatically = true - if (isLocalFile) { - val touchedFile = intent.getStringExtra("TOUCHED_FILE") - if (!touchedFile.isNullOrEmpty()) { - val localFilePath = File(MainApplication.context.getExternalFilesDir(null), touchedFile).absolutePath - activityWebViewBinding.contentWebView.wv.loadUrl("file://$localFilePath") - } - } else { - // Existing remote URL loading logic - val headers = mapOf("Authorization" to Utilities.header) - activityWebViewBinding.contentWebView.wv.loadUrl(link, headers) - } +// if (isLocalFile) { +// val touchedFile = intent.getStringExtra("TOUCHED_FILE") +// if (!touchedFile.isNullOrEmpty()) { +// val localFilePath = File(MainApplication.context.getExternalFilesDir(null), touchedFile).absolutePath +// activityWebViewBinding.contentWebView.wv.loadUrl("file://$localFilePath") +// } +// } else { +// val headers = mapOf("Authorization" to Utilities.header) +// activityWebViewBinding.contentWebView.wv.loadUrl(link, headers) +// } activityWebViewBinding.contentWebView.finish.setOnClickListener { finish() } setWebClient() } + private suspend fun loadLocalHtmlResource(resourceId: String?) { + withContext(Dispatchers.IO) { + try { + withContext(Dispatchers.Main) { + activityWebViewBinding.contentWebView.pBar.visibility = View.VISIBLE + } + + ensureResourceDownloaded(resourceId) + + val htmlContent = retrieveHtmlContentFromRealm(resourceId) + Log.d("okuro", "html content: $htmlContent") + + if (htmlContent != null) { + withContext(Dispatchers.Main) { + try { + // Create games directory in app's files directory + val gamesDir = File(filesDir, "games") + gamesDir.mkdirs() + + // Create resource-specific directory + val resourceDir = File(gamesDir, resourceId) + resourceDir.mkdirs() + + val htmlFile = File(resourceDir, "index.html") + htmlFile.writeText(htmlContent) + + // Create necessary directories + File(resourceDir, "js").mkdirs() + File(resourceDir, "style").mkdirs() + File(resourceDir, "style/fonts").mkdirs() + File(resourceDir, "meta").mkdirs() + + // Copy all required files + copyJsFiles(resourceDir) + copyCssFiles(resourceDir) + copyFontFiles(resourceDir) + copyMetaFiles(resourceDir) + + // Create URI using FileProvider + val contentUri = FileProvider.getUriForFile( + this@WebViewActivity, + "${packageName}.fileprovider", + htmlFile + ) + + // Grant read permission to WebView + activityWebViewBinding.contentWebView.wv.settings.allowFileAccess = true + activityWebViewBinding.contentWebView.wv.settings.allowFileAccessFromFileURLs = true + activityWebViewBinding.contentWebView.wv.loadUrl(contentUri.toString()) + Log.d("okuro", "Loading from: ${contentUri}") + } catch (e: Exception) { + Log.e("WebViewActivity", "Error preparing HTML content", e) + e.printStackTrace() + } finally { + activityWebViewBinding.contentWebView.pBar.visibility = View.GONE + } + } + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Error loading local HTML", e) + withContext(Dispatchers.Main) { + activityWebViewBinding.contentWebView.pBar.visibility = View.GONE + } + } + } + } + + private suspend fun copyJsFiles(resourceDir: File) { + withContext(Dispatchers.IO) { + val jsDir = File(resourceDir, "js") + copyFiles(resourceDir, "js/", "application/javascript", jsDir) + } + } + + private suspend fun copyCssFiles(resourceDir: File) { + withContext(Dispatchers.IO) { + val styleDir = File(resourceDir, "style") + copyFiles(resourceDir, "style/", "text/css", styleDir) + } + } + + private suspend fun copyFontFiles(resourceDir: File) { + withContext(Dispatchers.IO) { + val fontsDir = File(resourceDir, "style/fonts") + val fontTypes = listOf( + "application/font-woff", + "application/vnd.ms-fontobject", + "image/svg+xml" + ) + fontTypes.forEach { type -> + copyFiles(resourceDir, "style/fonts/", type, fontsDir) + } + } + } + + private suspend fun copyMetaFiles(resourceDir: File) { + withContext(Dispatchers.IO) { + val metaDir = File(resourceDir, "meta") + copyFiles(resourceDir, "meta/", "image/png", metaDir) + } + } + + private suspend fun copyFiles(resourceDir: File, prefix: String, contentType: String, destDir: File) { + val realm = Realm.getDefaultInstance() + try { + val libraryItem = realm.where(RealmMyLibrary::class.java) + .equalTo("_id", resourceId) + .findFirst() + + val attachments = libraryItem?.attachments?.filter { + it.name?.startsWith(prefix) == true && it.contentType == contentType + } + + attachments?.forEach { attachment -> + val fileName = attachment.name?.substringAfterLast("/") + if (fileName != null) { + val destFile = File(destDir, fileName) + + val fullAttachment = realm.where(RealmAttachment::class.java) + .equalTo("id", attachment.id) + .findFirst() + + fullAttachment?.let { + val fileContent = readAttachmentContent(it) + if (fileContent != null) { + destFile.writeText(fileContent) + Log.d("WebViewActivity", "Copied file: ${attachment.name}") + } + } + } + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Error copying files for prefix $prefix", e) + } finally { + realm.close() + } + } + + private suspend fun retrieveHtmlContentFromRealm(resourceId: String?): String? { + return withContext(Dispatchers.IO) { + val realm = Realm.getDefaultInstance() + try { + val libraryItem = realm.where(RealmMyLibrary::class.java) + .equalTo("_id", resourceId) + .findFirst() + + val htmlAttachment = libraryItem?.attachments?.firstOrNull { + it.name == "index.html" + } + + Log.d("okuro", "htmlAttachment: $htmlAttachment") + + htmlAttachment?.let { attachment -> + realm.where(RealmAttachment::class.java) + .equalTo("id", attachment.id) + .findFirst() + ?.let { fullAttachment -> + readAttachmentContent(fullAttachment) + } + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Error retrieving HTML from Realm", e) + null + } finally { + realm.close() + } + } + } + + private suspend fun readAttachmentContent(attachment: RealmAttachment): String? { + return withContext(Dispatchers.IO) { + val file = File(MainApplication.context.getExternalFilesDir(null), attachment.name) + Log.d("WebViewActivity", "Checking file: ${file.absolutePath}, exists: ${file.exists()}") + if (file.exists()) { + file.readText() + } else { + null + } + } + } + + private suspend fun ensureResourceDownloaded(resourceId: String?) { + if (resourceId == null) return + + withContext(Dispatchers.IO) { + val resourceDir = createResourceDirectoryStructure(resourceId) + val realm = Realm.getDefaultInstance() + + try { + Log.d("WebViewActivity", "Looking for resource with ID: $resourceId") + val libraryItem = realm.where(RealmMyLibrary::class.java) + .equalTo("_id", resourceId) + .findFirst() + + if (libraryItem == null) { + Log.e("WebViewActivity", "Library item not found for ID: $resourceId") + return@withContext + } + + Log.d("WebViewActivity", "Found library item with ${libraryItem.attachments?.size} attachments") + + libraryItem.attachments?.forEach { attachment -> + if (attachment.isStub) { + val destFile = File(resourceDir, attachment.name) + if (!destFile.exists()) { + Log.d("WebViewActivity", "Attempting to download: ${attachment.name}") + try { + val content = downloadAttachmentContent(attachment) + if (content != null) { + destFile.parentFile?.mkdirs() + destFile.writeText(content) + Log.d("WebViewActivity", "Successfully saved: ${attachment.name}") + } else { + Log.e("WebViewActivity", "Failed to download: ${attachment.name}") + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Error downloading ${attachment.name}", e) + } + } else { + Log.d("WebViewActivity", "File already exists: ${attachment.name}") + } + } + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Error in ensureResourceDownloaded", e) + } finally { + realm.close() + } + } + } + + private suspend fun downloadAttachmentContent(attachment: RealmAttachment): String? { + return withContext(Dispatchers.IO) { + val realm = Realm.getDefaultInstance() + try { + val libraryItem = realm.where(RealmMyLibrary::class.java) + .equalTo("_id", resourceId) + .findFirst() + + Log.d("WebViewActivity", "Found library item: ${libraryItem?._id}") + Log.d("WebViewActivity", "Remote address: ${libraryItem?.resourceRemoteAddress}") + + val remoteAddress = libraryItem?.resourceRemoteAddress + if (remoteAddress == null) { + Log.e("WebViewActivity", "Remote address not found for resource") + return@withContext null + } + + val baseUrl = if (remoteAddress.contains("@")) { + val urlParts = remoteAddress.split("@") + val auth = urlParts[0] + val restOfUrl = urlParts[1] + "${Utilities.getUrl()}$restOfUrl" + } else { + remoteAddress + }.substringBeforeLast("/") + + val attachmentUrl = "$baseUrl/${attachment.name}" + Log.d("WebViewActivity", "Attempting to download from: $attachmentUrl") + + try { + val url = URL(attachmentUrl) + val connection = url.openConnection() as HttpURLConnection + connection.requestMethod = "GET" + + if (remoteAddress.contains("@")) { + val auth = remoteAddress.split("@")[0].split("://")[1] + val base64Auth = android.util.Base64.encodeToString( + auth.toByteArray(), + android.util.Base64.NO_WRAP + ) + connection.setRequestProperty("Authorization", "Basic $base64Auth") + } + + try { + val responseCode = connection.responseCode + Log.d("WebViewActivity", "Response code for ${attachment.name}: $responseCode") + + if (responseCode == HttpURLConnection.HTTP_OK) { + val content = connection.inputStream.bufferedReader().use { it.readText() } + + val localFile = File(MainApplication.context.getExternalFilesDir(null), attachment.name) + localFile.parentFile?.mkdirs() + localFile.writeText(content) + + Log.d("WebViewActivity", "Successfully downloaded ${attachment.name}") + return@withContext content + } else { + val errorStream = connection.errorStream?.bufferedReader()?.use { it.readText() } + Log.e("WebViewActivity", "Failed to download attachment: HTTP $responseCode") + Log.e("WebViewActivity", "Error response: $errorStream") + return@withContext null + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Connection error for ${attachment.name}", e) + return@withContext null + } finally { + connection.disconnect() + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Error processing URL for ${attachment.name}", e) + return@withContext null + } + } catch (e: Exception) { + Log.e("WebViewActivity", "Error in Realm query", e) + return@withContext null + } finally { + realm.close() + } + } + } + + private fun createResourceDirectoryStructure(resourceId: String): File { + val gamesDir = File(filesDir, "games") + gamesDir.mkdirs() + + val resourceDir = File(gamesDir, resourceId) + resourceDir.mkdirs() + + File(resourceDir, "js").mkdirs() + File(resourceDir, "style").mkdirs() + File(resourceDir, "style/fonts").mkdirs() + File(resourceDir, "meta").mkdirs() + + return resourceDir + } private fun setWebClient() { activityWebViewBinding.contentWebView.wv.webViewClient = object : WebViewClient() { + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? { + if (request == null) return null + + val url = request.url.toString() + val gamesDir = File(filesDir, "games") + val resourceDir = File(gamesDir, resourceId) + + try { + // Handle JS files + if (url.contains("/js/")) { + val fileName = url.substringAfterLast("/") + val file = File(resourceDir, "js/$fileName") + if (file.exists()) { + return WebResourceResponse( + "application/javascript", + "UTF-8", + file.inputStream() + ) + } + } + + // Handle CSS files + if (url.contains("/style/") && !url.contains("/fonts/")) { + val fileName = url.substringAfterLast("/") + val file = File(resourceDir, "style/$fileName") + if (file.exists()) { + return WebResourceResponse( + "text/css", + "UTF-8", + file.inputStream() + ) + } + } + + // Handle font files + if (url.contains("/fonts/")) { + val fileName = url.substringAfterLast("/") + val file = File(resourceDir, "style/fonts/$fileName") + if (file.exists()) { + val mimeType = when { + fileName.endsWith(".woff") -> "application/font-woff" + fileName.endsWith(".eot") -> "application/vnd.ms-fontobject" + fileName.endsWith(".svg") -> "image/svg+xml" + else -> "application/octet-stream" + } + return WebResourceResponse(mimeType, "UTF-8", file.inputStream()) + } + } + + // Handle meta files + if (url.contains("/meta/")) { + val fileName = url.substringAfterLast("/") + val file = File(resourceDir, "meta/$fileName") + if (file.exists()) { + return WebResourceResponse( + "image/png", + "UTF-8", + file.inputStream() + ) + } + } + + Log.d("WebViewActivity", "Resource not found: $url") + } catch (e: Exception) { + Log.e("WebViewActivity", "Error intercepting request: $url", e) + } + + return super.shouldInterceptRequest(view, request) + } + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { super.onPageStarted(view, url, favicon) if (url.endsWith("/eng/")) { @@ -80,10 +499,6 @@ class WebViewActivity : AppCompatActivity() { val i = Uri.parse(url) activityWebViewBinding.contentWebView.webSource.text = i.host } - - override fun onPageFinished(view: WebView, url: String) { - super.onPageFinished(view, url) - } } } @@ -112,5 +527,4 @@ class WebViewActivity : AppCompatActivity() { } } } - } diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml index 8248868e52..b8ff724e09 100644 --- a/app/src/main/res/xml/file_paths.xml +++ b/app/src/main/res/xml/file_paths.xml @@ -1,4 +1,5 @@ + \ No newline at end of file From d558e4f6cf0a4795e78f508e66ab0638b575d385 Mon Sep 17 00:00:00 2001 From: Gideon Okuro Date: Fri, 13 Dec 2024 23:04:20 +0300 Subject: [PATCH 7/7] download and attempt to render html --- .../myplanet/ui/viewer/WebViewActivity.kt | 153 +++++++----------- 1 file changed, 59 insertions(+), 94 deletions(-) diff --git a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt index 00211064e7..ee89b179c2 100644 --- a/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt +++ b/app/src/main/java/org/ole/planet/myplanet/ui/viewer/WebViewActivity.kt @@ -98,59 +98,54 @@ class WebViewActivity : AppCompatActivity() { activityWebViewBinding.contentWebView.pBar.visibility = View.VISIBLE } - ensureResourceDownloaded(resourceId) + // Create resource directory structure + val gamesDir = File(filesDir, "games") + val resourceDir = File(gamesDir, resourceId) + resourceDir.mkdirs() - val htmlContent = retrieveHtmlContentFromRealm(resourceId) - Log.d("okuro", "html content: $htmlContent") + // Create necessary directories + File(resourceDir, "js").mkdirs() + File(resourceDir, "style").mkdirs() + File(resourceDir, "style/fonts").mkdirs() + File(resourceDir, "meta").mkdirs() + // Copy all required files + copyJsFiles(resourceDir) + copyCssFiles(resourceDir) + copyFontFiles(resourceDir) + copyMetaFiles(resourceDir) + + // Get HTML content and write to file + val htmlContent = retrieveHtmlContentFromRealm(resourceId) if (htmlContent != null) { + val htmlFile = File(resourceDir, "index.html") + htmlFile.writeText(htmlContent) + withContext(Dispatchers.Main) { try { - // Create games directory in app's files directory - val gamesDir = File(filesDir, "games") - gamesDir.mkdirs() - - // Create resource-specific directory - val resourceDir = File(gamesDir, resourceId) - resourceDir.mkdirs() - - val htmlFile = File(resourceDir, "index.html") - htmlFile.writeText(htmlContent) - - // Create necessary directories - File(resourceDir, "js").mkdirs() - File(resourceDir, "style").mkdirs() - File(resourceDir, "style/fonts").mkdirs() - File(resourceDir, "meta").mkdirs() - - // Copy all required files - copyJsFiles(resourceDir) - copyCssFiles(resourceDir) - copyFontFiles(resourceDir) - copyMetaFiles(resourceDir) - - // Create URI using FileProvider - val contentUri = FileProvider.getUriForFile( - this@WebViewActivity, - "${packageName}.fileprovider", - htmlFile - ) - - // Grant read permission to WebView - activityWebViewBinding.contentWebView.wv.settings.allowFileAccess = true - activityWebViewBinding.contentWebView.wv.settings.allowFileAccessFromFileURLs = true - activityWebViewBinding.contentWebView.wv.loadUrl(contentUri.toString()) - Log.d("okuro", "Loading from: ${contentUri}") + // Load the file directly using file:// protocol + val fileUrl = "file://${htmlFile.absolutePath}" + Log.d("WebViewActivity", "Loading URL: $fileUrl") + + activityWebViewBinding.contentWebView.wv.settings.apply { + allowFileAccess = true + allowFileAccessFromFileURLs = true + allowUniversalAccessFromFileURLs = true + domStorageEnabled = true + javaScriptEnabled = true + } + + activityWebViewBinding.contentWebView.wv.loadUrl(fileUrl) } catch (e: Exception) { - Log.e("WebViewActivity", "Error preparing HTML content", e) + Log.e("WebViewActivity", "Error loading HTML file", e) e.printStackTrace() - } finally { - activityWebViewBinding.contentWebView.pBar.visibility = View.GONE } } } + } catch (e: Exception) { - Log.e("WebViewActivity", "Error loading local HTML", e) + Log.e("WebViewActivity", "Error in loadLocalHtmlResource", e) + } finally { withContext(Dispatchers.Main) { activityWebViewBinding.contentWebView.pBar.visibility = View.GONE } @@ -420,67 +415,31 @@ class WebViewActivity : AppCompatActivity() { private fun setWebClient() { activityWebViewBinding.contentWebView.wv.webViewClient = object : WebViewClient() { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? { if (request == null) return null val url = request.url.toString() + Log.d("WebViewActivity", "Intercepting request: $url") + val gamesDir = File(filesDir, "games") val resourceDir = File(gamesDir, resourceId) try { - // Handle JS files - if (url.contains("/js/")) { - val fileName = url.substringAfterLast("/") - val file = File(resourceDir, "js/$fileName") - if (file.exists()) { - return WebResourceResponse( - "application/javascript", - "UTF-8", - file.inputStream() - ) - } - } - - // Handle CSS files - if (url.contains("/style/") && !url.contains("/fonts/")) { - val fileName = url.substringAfterLast("/") - val file = File(resourceDir, "style/$fileName") - if (file.exists()) { - return WebResourceResponse( - "text/css", - "UTF-8", - file.inputStream() - ) - } - } - - // Handle font files - if (url.contains("/fonts/")) { - val fileName = url.substringAfterLast("/") - val file = File(resourceDir, "style/fonts/$fileName") - if (file.exists()) { - val mimeType = when { - fileName.endsWith(".woff") -> "application/font-woff" - fileName.endsWith(".eot") -> "application/vnd.ms-fontobject" - fileName.endsWith(".svg") -> "image/svg+xml" - else -> "application/octet-stream" - } - return WebResourceResponse(mimeType, "UTF-8", file.inputStream()) - } - } - - // Handle meta files - if (url.contains("/meta/")) { - val fileName = url.substringAfterLast("/") - val file = File(resourceDir, "meta/$fileName") - if (file.exists()) { - return WebResourceResponse( - "image/png", - "UTF-8", - file.inputStream() - ) + // Extract the path from the URL + val path = url.substringAfter("file://") + val file = File(path) + + if (file.exists()) { + val mimeType = when { + url.endsWith(".js") -> "application/javascript" + url.endsWith(".css") -> "text/css" + url.endsWith(".woff") -> "application/font-woff" + url.endsWith(".eot") -> "application/vnd.ms-fontobject" + url.endsWith(".svg") -> "image/svg+xml" + url.endsWith(".png") -> "image/png" + else -> "text/plain" } + return WebResourceResponse(mimeType, "UTF-8", file.inputStream()) } Log.d("WebViewActivity", "Resource not found: $url") @@ -499,6 +458,12 @@ class WebViewActivity : AppCompatActivity() { val i = Uri.parse(url) activityWebViewBinding.contentWebView.webSource.text = i.host } + + override fun onPageFinished(view: WebView?, url: String?) { + super.onPageFinished(view, url) + Log.d("WebViewActivity", "Page finished loading: $url") + activityWebViewBinding.contentWebView.pBar.visibility = View.GONE + } } }