From 4276c16a98156bbef86ec7b27503274458fc674e Mon Sep 17 00:00:00 2001 From: Kieran BW <41634689+FredHappyface@users.noreply.github.com> Date: Thu, 3 Mar 2022 00:33:07 +0000 Subject: [PATCH] add help docs, refactor import and sending functionality --- CHANGELOG.md | 2 + HELP.md | 95 +++++++++++ README.md | 5 + TUTORIAL.md | 14 +- app/src/main/AndroidManifest.xml | 2 +- .../fredhappyface/ewesticker/ImageKeyboard.kt | 125 ++------------- .../fredhappyface/ewesticker/MainActivity.kt | 99 ++---------- .../ewesticker/StickerImporter.kt | 94 +++++++++++ .../fredhappyface/ewesticker/StickerSender.kt | 151 ++++++++++++++++++ .../com/fredhappyface/ewesticker/Toaster.kt | 17 +- app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values/strings.xml | 3 +- 12 files changed, 394 insertions(+), 214 deletions(-) create mode 100644 HELP.md create mode 100644 app/src/main/java/com/fredhappyface/ewesticker/StickerImporter.kt create mode 100644 app/src/main/java/com/fredhappyface/ewesticker/StickerSender.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 7deabba..2bee6b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ patch-level version changes can be found in [commit messages](../../commits/mast ## Next_Ver - 2022/xx/xx - New Feature: Improve error messages for the user per https://github.com/FredHappyface/Android.EweSticker/issues/39 +- New Feature: Add help (HELP.md) to provide guidance for error messages +- Bugfix: Refactor in response bug found when investigating https://github.com/FredHappyface/Android.EweSticker/issues/37 - Bugfix: Back button now enabled in fresh install per https://github.com/FredHappyface/Android.EweSticker/issues/38 - Update navbar theme (dark/light rather than the app accent colour) - Update dependencies diff --git a/HELP.md b/HELP.md new file mode 100644 index 0000000..5726ccf --- /dev/null +++ b/HELP.md @@ -0,0 +1,95 @@ + + +# Help Guide + +Support is provided via GitHub issues, please note this is provided on a voluntary basis + +Please take a look at [Error Codes](#error-codes) first. This may provide some useful information +for why you are getting a certain error code. If an issue is created that is answered by this section +you'll likely be asked if you've read this :) + +- [Error Codes](#error-codes) + - [E031](#e031) + - [E032](#e032) + - [E033](#e033) + - [E040](#e040) + - [E041](#e041) + - [E050](#e050) +- [Reach out](#reach-out) + +## Error Codes + +### E031 +Some stickers failed to import (some number imported). Max stickers reached + +This means that the total number of stickers that you are trying to import exceeds the +maximum number of stickers supported by EweSticker. Try and import fewer stickers, +see [Tutorial](/TUTORIAL.md) + +**NOTE:** that the maximum pack size is currently **128** and the total maximum number of stickers supported +is **4096** + +If you feel strongly that the maximum limit should be increased, open an issue (use the +'Question' template) and make a request - Be sure to explain why this would be useful. Simply saying +'I want 20000 stickers!' will likely result in the issue being closed + +### E032 +Some stickers failed to import (some number imported). Max pack size reached + +This means that one of your sticker packs contains a number of stickers that exceeds the +maximum pack size supported by EweSticker. Try splitting the pack up into smaller chunks, +see [Tutorial](/TUTORIAL.md) + +**NOTE:** that the maximum pack size is currently **128** and the total maximum number of stickers supported +is **4096** + +If you feel strongly that the maximum limit should be increased, open an issue (use the +'Question' template) and make a request - Be sure to explain why this would be useful. Simply saying +'I want 20000 stickers!' will likely result in the issue being closed + +### E033 +Some stickers failed to import (some number imported). Unsupported formats found + +This could be for a few reasons, perhaps you have a non sticker file in the sticker directory such +as a document in the wrong place. Alternatively this may result in a seemingly valid sticker not being +imported. Chances are that the sticker is not in a [supported format](/README.md#features). + +### E040 +(image type) not supported here + +The application you are using doesn't support a sticker format or the compat-format + +Unfortunately, nothing can be done by EweSticker to solve this, you may need to contact the application +developer you are trying to send a sticker to + +### E041 +Unexpected IOException when converting sticker + +This is an unexpected error and happened when creating a compat-sticker to send to the application. +Please open an issue and provide as much information as you can. E.g. Android Version, phone +manufacturer, app you are trying to send the sticker in + +### E050 +IllegalStateException when switching packs. Try switching away from and back to EweSticker + +This sometimes happens if you leave EweSticker as the current keyboard and switch back to it. The best +way to solve this is to tap the back button in the pack selector and switch back to EweSticker. +Please open an issue and provide as much information as you can. E.g. Android Version, phone +manufacturer, app you are trying to send the sticker in. + +## Reach out + +Support is provided via GitHub issues, please note this is provided on a voluntary basis + +you are therefore not entitled to free customer service (that is not to say that contributions/ issues and questions are not welcome - more reminding you that project maintainers are well within their rights to prioritize other issues). + +https://github.com/FredHappyface/.github/blob/master/SUPPORT.md provides a little more info +from the types of support you can expect + +Please make sure to read https://github.com/FredHappyface/Android.EweSticker/issues/21 before +opening an issue, this ay seem a bit grumpy but chances are I won't be able to help with your +issue if you do not fill in the template provided + +To open a new issue click the following link: https://github.com/FredHappyface/Android.EweSticker/issues/new/choose + +**NOTE:** you will need to have a GitHub account to open issues (create one at https://github.com/signup) diff --git a/README.md b/README.md index cf9480a..8b8761d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Sticker-board for android inspired by uSticker (forked from woosticker). - [Features](#features) - [Screenshots](#screenshots) - [How to use](#how-to-use) +- [Help](#help) - [Lint with](#lint-with) - [Language Information](#language-information) - [Kotlin and Android Version](#kotlin-and-android-version) @@ -72,6 +73,10 @@ Sticker-board for android inspired by uSticker (forked from woosticker). See the [Tutorial](/TUTORIAL.md) for more information. +## Help + +See the [Help](/HELP.md) for more information. + ## Lint with ```txt diff --git a/TUTORIAL.md b/TUTORIAL.md index 593a474..390a1d4 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -1,9 +1,18 @@ - + # Tutorial See below for a step-by-step tutorial on how to use EweSticker with your existing sticker collection. +- [Step 1 - Create Sticker Directory (and transfer to device)](#step-1---create-sticker-directory-and-transfer-to-device) +- [Step 2 - Download EweSticker](#step-2---download-ewesticker) + - [Get it on F-Droid](#get-it-on-f-droid) + - [Get it on Google Play](#get-it-on-google-play) + - [Download the APK](#download-the-apk) +- [Step 3 - Select Directory with EweSticker (and wait...)](#step-3---select-directory-with-ewesticker-and-wait) +- [Step 4 - Activate the keyboard](#step-4---activate-the-keyboard) +- [Step 5 - Send Stickers in your favourite apps](#step-5---send-stickers-in-your-favourite-apps) + ## Step 1 - Create Sticker Directory (and transfer to device) Step 1 @@ -23,6 +32,9 @@ The sticker directory has the following structure: Then transfer this to your phone/ device. Plugging this into a PC is a pretty convenient way to do this. +**NOTE:** that the maximum pack size is currently **128** and the total maximum number of stickers supported +is **4096** + ## Step 2 - Download EweSticker ### Get it on F-Droid diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6e07ee6..8d395da 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ android:label="@string/app_name" android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning" - android:dataExtractionRules="@xml/data_extraction_rules"> + android:dataExtractionRules="@xml/data_extraction_rules" tools:targetApi="s"> + private lateinit var stickerSender: StickerSender // onCreateInputView private lateinit var keyboardRoot: ViewGroup @@ -83,7 +71,7 @@ class ImageKeyboard : InputMethodService() { override fun onCreate() { // Misc super.onCreate() - val scale = applicationContext.resources.displayMetrics.density + val scale = baseContext.resources.displayMetrics.density // Setup coil val imageLoader = ImageLoader.Builder(baseContext) @@ -112,7 +100,7 @@ class ImageKeyboard : InputMethodService() { (this.sharedPreferences.getInt("iconSize", 80) * scale) }) .toInt() - this.toaster = Toaster(applicationContext) + this.toaster = Toaster(baseContext) // Load Packs this.loadedPacks = HashMap() val packs = @@ -145,7 +133,7 @@ class ImageKeyboard : InputMethodService() { * @return View keyboardLayout */ override fun onCreateInputView(): View { - val keyboardLayout = View.inflate(applicationContext, R.layout.keyboard_layout, null) + val keyboardLayout = View.inflate(baseContext, R.layout.keyboard_layout, null) this.keyboardRoot = keyboardLayout.findViewById(R.id.keyboardRoot) this.packsList = keyboardLayout.findViewById(R.id.packsList) this.packContent = keyboardLayout.findViewById(R.id.packContent) @@ -183,8 +171,15 @@ class ImageKeyboard : InputMethodService() { * @param restarting */ override fun onStartInput(info: EditorInfo?, restarting: Boolean) { - this.supportedMimes = - Utils.getSupportedMimes().filter { isCommitContentSupported(info, it) } + this.stickerSender = StickerSender( + this.baseContext, + this.toaster, + this.internalDir, + this.currentInputConnection, + this.currentInputEditorInfo, + this.compatCache, + this.imageLoader + ) } /** When leaving some input field update the caches */ @@ -197,91 +192,6 @@ class ImageKeyboard : InputMethodService() { super.onFinishInput() } - /** - * In the event that a mimetype is unsupported by a InputConnectionCompat (looking at you, - * Signal) create a temporary png and send that. In the event that png is not supported, alert - * the user. - * - * @param file: File - */ - private suspend fun doFallbackCommitContent(file: File) { - // PNG might not be supported - if ("image/png" !in this.supportedMimes) { - toaster.toast(getString(R.string.fallback_040, file.extension)) - return - } - // Create a new compatSticker and convert the sticker to png - val compatStickerName = file.hashCode().toString() - val compatSticker = File(this.internalDir, "__compatSticker__/$compatStickerName.png") - if (!compatSticker.exists()) { - // If the sticker doesn't exist then create - compatSticker.parentFile?.mkdirs() - try { - val request = - ImageRequest.Builder(baseContext) - .data(file) - .target { result -> - val bitmap = result.toBitmap() - bitmap.compress( - Bitmap.CompressFormat.PNG, 90, FileOutputStream(compatSticker) - ) - } - .build() - imageLoader.execute(request) - } catch (ignore: IOException) { - toaster.toast(getString(R.string.fallback_041)) - } - } - // Send the compatSticker! - doCommitContent("image/png", compatSticker) - // Remove old stickers - val remSticker = this.compatCache.add(compatStickerName) - remSticker?.let { File(this.internalDir, "__compatSticker__/$remSticker.png").delete() } - } - - /** - * Send a sticker file to a InputConnectionCompat - * - * @param mimeType String - * @param file File - */ - private fun doCommitContent(mimeType: String, file: File) { - // ContentUri, ClipDescription, linkUri - val inputContentInfoCompat = - InputContentInfoCompat( - FileProvider.getUriForFile(this, "com.fredhappyface.ewesticker.inputcontent", file), - ClipDescription(file.name, arrayOf(mimeType)), - null - ) - // InputConnection, EditorInfo, InputContentInfoCompat, int flags, null opts - InputConnectionCompat.commitContent( - currentInputConnection, - currentInputEditorInfo, - inputContentInfoCompat, - InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION, - null - ) - } - - /** - * Check if the sticker is supported by the receiver - * - * @param editorInfo: EditorInfo - the editor/ receiver - * @param mimeType: String - the image mimetype - * @return boolean - is the mimetype supported? - */ - private fun isCommitContentSupported(editorInfo: EditorInfo?, mimeType: String?): Boolean { - editorInfo?.packageName ?: return false - mimeType ?: return false - currentInputConnection ?: return false - EditorInfoCompat.getContentMimeTypes(editorInfo).forEach { - if (ClipDescription.compareMimeTypes(mimeType, it)) { - return true - } - } - return false - } - /** * Swap the pack layout every time a pack is selected. If already cached use that otherwise * create the pack layout @@ -362,12 +272,7 @@ class ImageKeyboard : InputMethodService() { imgButton.setOnClickListener { val file = it.tag as File this.recentCache.add(file.absolutePath) - val stickerType = Utils.getMimeType(file) - if (stickerType == null || stickerType !in this.supportedMimes) { - CoroutineScope(Dispatchers.Main).launch { doFallbackCommitContent(file) } - return@setOnClickListener - } - doCommitContent(stickerType, file) + stickerSender.sendSticker(file) } imgButton.setOnLongClickListener { view: View -> val file = view.tag as File @@ -415,7 +320,7 @@ class ImageKeyboard : InputMethodService() { if (SDK_INT >= 28) { this.switchToPreviousInputMethod() } else { - (applicationContext.getSystemService(INPUT_METHOD_SERVICE) as + (baseContext.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager) .showInputMethodPicker() } diff --git a/app/src/main/java/com/fredhappyface/ewesticker/MainActivity.kt b/app/src/main/java/com/fredhappyface/ewesticker/MainActivity.kt index b2cff4e..9d271b3 100644 --- a/app/src/main/java/com/fredhappyface/ewesticker/MainActivity.kt +++ b/app/src/main/java/com/fredhappyface/ewesticker/MainActivity.kt @@ -3,7 +3,6 @@ package com.fredhappyface.ewesticker import android.app.Activity import android.content.Intent import android.content.SharedPreferences -import android.net.Uri import android.os.Bundle import android.os.Handler import android.os.Looper @@ -16,31 +15,18 @@ import android.widget.SeekBar.OnSeekBarChangeListener import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.documentfile.provider.DocumentFile import androidx.preference.PreferenceManager -import java.io.File -import java.nio.file.Files import java.util.* import java.util.concurrent.Executors -private const val MAX_FILES = 4096 -private const val MAX_PACK_SIZE = 128 /** MainActivity class inherits from the AppCompatActivity class - provides the settings view */ class MainActivity : AppCompatActivity() { - // init - private val supportedMimes = Utils.getSupportedMimes() - // onCreate private lateinit var sharedPreferences: SharedPreferences private lateinit var contextView: View private lateinit var toaster: Toaster - // importSticker(s) - private var filesLeft = MAX_FILES - private var packSizes: MutableMap = mutableMapOf() - private var totalStickers = 0 - /** * Sets up content view, shared prefs, etc. * @@ -53,7 +39,7 @@ class MainActivity : AppCompatActivity() { // Set late-init attrs this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) this.contextView = findViewById(R.id.activityMainRoot) - this.toaster = Toaster(applicationContext) + this.toaster = Toaster(baseContext) refreshStickerDirPath() // Update UI with config seekBar(findViewById(R.id.iconsPerXSb), findViewById(R.id.iconsPerXLbl), "iconsPerX", 3) @@ -72,13 +58,14 @@ class MainActivity : AppCompatActivity() { registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_OK) { val editor = this.sharedPreferences.edit() - editor.putString("stickerDirPath", result.data?.data.toString()) + val stickerDirPath = result.data?.data.toString() + editor.putString("stickerDirPath", stickerDirPath) editor.putString("lastUpdateDate", Calendar.getInstance().time.toString()) editor.putString("recentCache", "") editor.putString("compatCache", "") editor.apply() refreshStickerDirPath() - importStickers() + importStickers(stickerDirPath) } } @@ -98,46 +85,14 @@ class MainActivity : AppCompatActivity() { * @param view: View */ fun chooseDir(view: View) { - this.filesLeft = MAX_FILES - this.totalStickers = 0 val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) chooseDirResultLauncher.launch(intent) } - /** - * Copies stickers from source to internal storage - * - * @param sticker sticker to copy over - * - * @return 1 if sticker imported successfully else 0 - */ - private fun importSticker(sticker: DocumentFile) { - // Exit if sticker is unsupported or if pack size > MAX_PACK_SIZE - val parentDir = sticker.parentFile?.name ?: "__default__" - val packSize = this.packSizes[parentDir] ?: 0 - if (packSize > MAX_PACK_SIZE) { - this.toaster.setState(2); return - } - if (sticker.type !in this.supportedMimes) { - this.toaster.setState(3); return - } - this.packSizes[parentDir] = packSize + 1 - // Copy sticker to app storage - val destSticker = File(filesDir, "stickers/${parentDir}/${sticker.name}") - destSticker.parentFile?.mkdirs() - try { - val inputStream = contentResolver.openInputStream(sticker.uri) - Files.copy(inputStream, destSticker.toPath()) - inputStream?.close() - } catch (e: java.lang.Exception) { - } - this.totalStickers++ - } - /** Import files from storage to internal directory */ - private fun importStickers() { + private fun importStickers(stickerDirPath: String) { // Use worker thread because this takes several seconds val executor = Executors.newSingleThreadExecutor() val handler = Handler(Looper.getMainLooper()) @@ -147,30 +102,21 @@ class MainActivity : AppCompatActivity() { val button = findViewById