From acd55f6d5ae5f1c9879f09258b93342f9dd83436 Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 25 Jan 2020 15:16:36 +0100 Subject: [PATCH] Work in creator activity and improvements in app Working on apng decoder --- .../src/main/java/oupson/apng/Apng.kt | 2 + .../src/main/java/oupson/apng/ApngAnimator.kt | 3 +- ...erimentalApngDecoder.kt => ApngDecoder.kt} | 16 +- .../src/main/java/oupson/apng/Loader.kt | 3 +- app-test/src/main/AndroidManifest.xml | 23 ++- .../oupson/apngcreator/CreatorActivity.kt | 183 ------------------ .../apngcreator/activities/CreatorActivity.kt | 146 ++++++++++++++ .../{ => activities}/MainActivity.kt | 45 ++++- .../{ => activities}/ViewerActivity.kt | 7 +- .../oupson/apngcreator/adapter/AnkoAdapter.kt | 29 --- .../apngcreator/adapter/ImageAdapter.kt | 72 +++++++ .../{ => fragments}/ApngDecoderFragment.kt | 12 +- .../{ => fragments}/JavaFragment.java | 7 +- .../{ => fragments}/KotlinFragment.kt | 8 +- .../apngcreator/views/SquareImageView.kt | 21 ++ ..._24dp.xml => ic_play_arrow_white_24dp.xml} | 2 +- .../src/main/res/layout/activity_creator.xml | 29 ++- .../src/main/res/layout/activity_main.xml | 3 +- .../src/main/res/layout/activity_viewer.xml | 3 +- .../main/res/layout/fragment_apng_decoder.xml | 2 +- .../src/main/res/layout/fragment_java.xml | 2 +- .../src/main/res/layout/fragment_kotlin.xml | 9 +- app-test/src/main/res/layout/list_image.xml | 45 +++++ app-test/src/main/res/menu/creator_menu.xml | 11 ++ app-test/src/main/res/values-night/bools.xml | 1 + app-test/src/main/res/values-night/colors.xml | 2 +- app-test/src/main/res/values/bools.xml | 1 + app-test/src/main/res/values/strings.xml | 8 +- app-test/src/main/res/values/styles.xml | 3 + app-test/src/main/res/xml/provider_paths.xml | 5 + 30 files changed, 432 insertions(+), 271 deletions(-) rename apng_library/src/main/java/oupson/apng/{ExperimentalApngDecoder.kt => ApngDecoder.kt} (97%) delete mode 100644 app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt create mode 100644 app-test/src/main/java/oupson/apngcreator/activities/CreatorActivity.kt rename app-test/src/main/java/oupson/apngcreator/{ => activities}/MainActivity.kt (79%) rename app-test/src/main/java/oupson/apngcreator/{ => activities}/ViewerActivity.kt (92%) delete mode 100644 app-test/src/main/java/oupson/apngcreator/adapter/AnkoAdapter.kt create mode 100644 app-test/src/main/java/oupson/apngcreator/adapter/ImageAdapter.kt rename app-test/src/main/java/oupson/apngcreator/{ => fragments}/ApngDecoderFragment.kt (81%) rename app-test/src/main/java/oupson/apngcreator/{ => fragments}/JavaFragment.java (89%) rename app-test/src/main/java/oupson/apngcreator/{ => fragments}/KotlinFragment.kt (95%) create mode 100644 app-test/src/main/java/oupson/apngcreator/views/SquareImageView.kt rename app-test/src/main/res/drawable/{ic_play_arrow_black_24dp.xml => ic_play_arrow_white_24dp.xml} (88%) create mode 100644 app-test/src/main/res/layout/list_image.xml create mode 100644 app-test/src/main/res/menu/creator_menu.xml create mode 100644 app-test/src/main/res/xml/provider_paths.xml diff --git a/apng_library/src/main/java/oupson/apng/Apng.kt b/apng_library/src/main/java/oupson/apng/Apng.kt index e7e821a..e48051b 100644 --- a/apng_library/src/main/java/oupson/apng/Apng.kt +++ b/apng_library/src/main/java/oupson/apng/Apng.kt @@ -17,6 +17,8 @@ import oupson.apng.utils.Utils.Companion.to4Bytes import java.io.File import java.util.zip.CRC32 + +// TODO CREATE A BETTER CLASS /** * Create an APNG file */ diff --git a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt index f0f9a1d..2ab2130 100644 --- a/apng_library/src/main/java/oupson/apng/ApngAnimator.kt +++ b/apng_library/src/main/java/oupson/apng/ApngAnimator.kt @@ -92,7 +92,7 @@ fun ImageView.loadApng(@RawRes res : Int, speed : Float? = null, apngAnimatorOpt /** * Class to play APNG - * For better performance but lesser features use [ExperimentalApngDecoder] instead + * For better performance but lesser features use [ApngDecoder] instead */ class ApngAnimator(private val context: Context?) { @Suppress("MemberVisibilityCanBePrivate") @@ -112,6 +112,7 @@ class ApngAnimator(private val context: Context?) { } private var imageView: ImageView? = null + @Suppress("MemberVisibilityCanBePrivate") var anim: CustomAnimationDrawable? = null private var activeAnimation: CustomAnimationDrawable? = null diff --git a/apng_library/src/main/java/oupson/apng/ExperimentalApngDecoder.kt b/apng_library/src/main/java/oupson/apng/ApngDecoder.kt similarity index 97% rename from apng_library/src/main/java/oupson/apng/ExperimentalApngDecoder.kt rename to apng_library/src/main/java/oupson/apng/ApngDecoder.kt index 6757e25..4bde879 100644 --- a/apng_library/src/main/java/oupson/apng/ExperimentalApngDecoder.kt +++ b/apng_library/src/main/java/oupson/apng/ApngDecoder.kt @@ -24,16 +24,14 @@ import java.io.InputStream import java.net.URL import java.util.zip.CRC32 -// TODO DOC CODE -class ExperimentalApngDecoder { +class ApngDecoder { interface Callback { fun onSuccess(drawable : Drawable) fun onError(error : java.lang.Exception) } companion object { - // TODO Change TAG - private const val TAG = "ExperimentalApngDecoder" + private const val TAG = "ApngDecoder" private val clearPaint : Paint by lazy { Paint().apply { @@ -378,7 +376,7 @@ class ExperimentalApngDecoder { * @param file File to decode. * @param imageView Image View. * @param speed Optional parameter. - * @param callback [ExperimentalApngDecoder.Callback] to handle success and error + * @param callback [ApngDecoder.Callback] to handle success and error */ @Suppress("unused") @JvmStatic @@ -406,7 +404,7 @@ class ExperimentalApngDecoder { * @param uri Uri to load * @param imageView Image View. * @param speed Optional parameter. - * @param callback [ExperimentalApngDecoder.Callback] to handle success and error + * @param callback [ApngDecoder.Callback] to handle success and error */ @Suppress("unused") @JvmStatic @@ -435,7 +433,7 @@ class ExperimentalApngDecoder { * @param res Raw resource to load * @param imageView Image View. * @param speed Optional parameter. - * @param callback [ExperimentalApngDecoder.Callback] to handle success and error + * @param callback [ApngDecoder.Callback] to handle success and error */ @Suppress("unused") @JvmStatic @@ -464,7 +462,7 @@ class ExperimentalApngDecoder { * @param url URL to load * @param imageView Image View. * @param speed Optional parameter. - * @param callback [ExperimentalApngDecoder.Callback] to handle success and error + * @param callback [ApngDecoder.Callback] to handle success and error */ @Suppress("unused") @JvmStatic @@ -492,7 +490,7 @@ class ExperimentalApngDecoder { * @param string URL to load * @param imageView Image View. * @param speed Optional parameter. - * @param callback [ExperimentalApngDecoder.Callback] to handle success and error + * @param callback [ApngDecoder.Callback] to handle success and error */ @Suppress("unused") @JvmStatic diff --git a/apng_library/src/main/java/oupson/apng/Loader.kt b/apng_library/src/main/java/oupson/apng/Loader.kt index 7b46062..6b12d3c 100644 --- a/apng_library/src/main/java/oupson/apng/Loader.kt +++ b/apng_library/src/main/java/oupson/apng/Loader.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.BufferedInputStream import java.io.File +import java.io.IOException import java.net.URL class Loader { @@ -15,7 +16,7 @@ class Loader { * @param url Url of the file to download * @return [ByteArray] of the file */ - // @Throws(IOException::class, java.io.FileNotFoundException::class, java.lang.Exception::class) + @Throws(IOException::class, java.io.FileNotFoundException::class) suspend fun load(context: Context, url: URL) = withContext(Dispatchers.IO) { val currentDir = context.filesDir diff --git a/app-test/src/main/AndroidManifest.xml b/app-test/src/main/AndroidManifest.xml index b6115e5..91cd072 100644 --- a/app-test/src/main/AndroidManifest.xml +++ b/app-test/src/main/AndroidManifest.xml @@ -16,7 +16,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + @@ -24,7 +24,7 @@ @@ -36,8 +36,23 @@ + android:name=".activities.CreatorActivity" + android:exported="true" + android:parentActivityName=".activities.MainActivity"> + + + + + + \ No newline at end of file diff --git a/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt b/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt deleted file mode 100644 index 8beb3be..0000000 --- a/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt +++ /dev/null @@ -1,183 +0,0 @@ -package oupson.apngcreator - -import android.app.Activity -import android.content.Intent -import android.content.res.ColorStateList -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.graphics.Color -import android.os.Bundle -import android.os.Environment -import android.view.View -import android.widget.CheckBox -import android.widget.ListView -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import com.google.android.material.floatingactionbutton.FloatingActionButton -import org.jetbrains.anko.* -import org.jetbrains.anko.design.appBarLayout -import org.jetbrains.anko.design.floatingActionButton -import org.jetbrains.anko.sdk27.coroutines.onClick -import oupson.apng.Apng -import oupson.apng.ApngAnimator -import oupson.apngcreator.adapter.AnkoAdapter -import java.io.File - -// TODO -class CreatorActivity : AppCompatActivity() { - companion object { - private const val PICK_IMAGE = 999 - } - private var items : ArrayList = ArrayList() - private var bitmapAdapter : AnkoAdapter? = null - - private var view = CreatorActivityLayout() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - view.setContentView(this) - view.addFrameButton.onClick { - val getIntent = Intent(Intent.ACTION_GET_CONTENT) - getIntent.type = "image/*" - - val pickIntent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI) - pickIntent.type = "image/*" - - val chooserIntent = Intent.createChooser(getIntent, "Select Image") - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(pickIntent)) - - startActivityForResult(chooserIntent, PICK_IMAGE) - } - view.createButton.onClick { - val apngCreated = Apng() - - items.forEach { bitmap -> - apngCreated.addFrames(bitmap) - } - - File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "apn0.png").writeBytes(apngCreated.toByteArray()) - - apngCreated.apply { - if (view.optimiseCheckBox.isChecked) - apngCreated.optimiseFrame() - } - val a = ApngAnimator(applicationContext) - File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "apn.png").writeBytes(apngCreated.toByteArray()) - a.load(apngCreated.toByteArray()) - a.onLoaded { anim -> - alert { - customView { - imageView { - this.setImageDrawable(anim.anim) - } - } - }.show() - } - } - bitmapAdapter = AnkoAdapter({items}) { index, items, _ -> - with(items[index]) { - verticalLayout { - lparams { - width = matchParent - height = matchParent - } - imageView { - setImageBitmap(this@with) - }.lparams { - width = matchParent - height = matchParent - } - } - } - } - /* frameListViewAdapter(this, items) */ - view.listView.adapter = bitmapAdapter - setSupportActionBar(view.toolbar) - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when(requestCode) { - PICK_IMAGE -> { - if (resultCode == Activity.RESULT_OK) { - if (data?.data != null) { - contentResolver.openInputStream(data.data!!)?.readBytes()?.apply { - items.add(BitmapFactory.decodeByteArray(this, 0, this.size)) - bitmapAdapter?.notifyDataSetChanged() - } - } - } - } - } - } -} - -class CreatorActivityLayout : AnkoComponent { - lateinit var listView: ListView - lateinit var addFrameButton: FloatingActionButton - lateinit var createButton: FloatingActionButton - lateinit var optimiseCheckBox: CheckBox - lateinit var toolbar: Toolbar - override fun createView(ui: AnkoContext) = with(ui) { - relativeLayout { - backgroundColor = Color.WHITE - val bar = verticalLayout { - id = View.generateViewId() - backgroundColor = Color.WHITE - appBarLayout { - /**toolbar = xToolbar { - id = View.generateViewId() - }.lparams { - width = matchParent - height = wrapContent - } - }.lparams { - width = matchParent - height = wrapContent - bottomMargin = 1 - }*/ - }.lparams { - width = matchParent - height = wrapContent - } - optimiseCheckBox = checkBox("Optimise APNG, WIP !") { - id = View.generateViewId() - }.lparams { - width = matchParent - //below(bar) - } - listView = listView { - id = View.generateViewId() - }.lparams { - width = matchParent - height = matchParent - //below(optimiseCheckBox) - } - addFrameButton = floatingActionButton { - imageResource = R.drawable.ic_add_black_24dp - imageTintList = ColorStateList.valueOf(Color.WHITE) - backgroundTintList = ColorStateList.valueOf(Color.BLACK) - isClickable = true - }.lparams { - width = wrapContent - height = wrapContent - margin = dip(5) - //alignParentBottom() - //alignParentEnd() - } - createButton = floatingActionButton { - imageResource = R.drawable.ic_play_arrow_black_24dp - imageTintList = ColorStateList.valueOf(Color.WHITE) - backgroundTintList = ColorStateList.valueOf(Color.BLACK) - isClickable = true - }.lparams { - width = wrapContent - height = wrapContent - margin = dip(5) - //alignParentBottom() - //alignParentStart() - } - } - } - } -} diff --git a/app-test/src/main/java/oupson/apngcreator/activities/CreatorActivity.kt b/app-test/src/main/java/oupson/apngcreator/activities/CreatorActivity.kt new file mode 100644 index 0000000..1e4eca2 --- /dev/null +++ b/app-test/src/main/java/oupson/apngcreator/activities/CreatorActivity.kt @@ -0,0 +1,146 @@ +package oupson.apngcreator.activities + +import android.app.Activity +import android.content.Intent +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.FileProvider +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.activity_creator.* +import oupson.apng.Apng +import oupson.apngcreator.BuildConfig +import oupson.apngcreator.R +import oupson.apngcreator.adapter.ImageAdapter +import java.io.File + +class CreatorActivity : AppCompatActivity() { + companion object { + private const val PICK_IMAGE = 999 + } + private var items : ArrayList = ArrayList() + private var adapter : ImageAdapter? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.activity_creator) + + fabAddImage.setOnClickListener { + val getIntent = Intent(Intent.ACTION_GET_CONTENT) + getIntent.type = "image/*" + + val pickIntent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + pickIntent.type = "image/*" + + val chooserIntent = Intent.createChooser(getIntent, "Select Image") + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(pickIntent)) + + startActivityForResult(chooserIntent, + PICK_IMAGE + ) + } + + /* frameListViewAdapter(this, items) */ + adapter = ImageAdapter(this, items) + + imageRecyclerView.layoutManager = LinearLayoutManager(this) + imageRecyclerView.setHasFixedSize(true) + imageRecyclerView.setItemViewCacheSize(20) + if (adapter != null) + ItemTouchHelper(SwipeToDeleteCallback(adapter!!)).attachToRecyclerView(imageRecyclerView) + + setSupportActionBar(creatorBottomAppBar) + imageRecyclerView.adapter = adapter + supportActionBar?.setDisplayHomeAsUpEnabled(true) + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.creator_menu, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + return when (item?.itemId) { + R.id.menu_create_apng -> { + // TODO + val apngCreated = Apng() + + items.forEachIndexed { i, uri -> + println("delay : ${adapter?.delay?.get(i)?.toFloat() ?: 1000f}ms") + val str = contentResolver.openInputStream(uri) + apngCreated.addFrames(BitmapFactory.decodeStream(str), delay = adapter?.delay?.get(i)?.toFloat() ?: 1000f) + str?.close() + } + + File(cacheDir, "apn0.png").writeBytes(apngCreated.toByteArray()) + + apngCreated.apply { + // TODO + //if (view.optimiseCheckBox.isChecked) + // apngCreated.optimiseFrame() + } + + // TODO Open + val f = File(filesDir, "images/apng.png").apply { + if (!exists()) { + parentFile.mkdirs() + println(createNewFile()) + } + writeBytes(apngCreated.toByteArray()) + } + + + val intent = Intent(Intent.ACTION_VIEW) + intent.data = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", f) + startActivity(intent) + + true + } + else -> super.onOptionsItemSelected(item) + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when(requestCode) { + PICK_IMAGE -> { + if (resultCode == Activity.RESULT_OK) { + if (data?.data != null) { + items.add(data.data!!) + adapter?.notifyDataSetChanged() + } + } + } + } + } + + inner class SwipeToDeleteCallback(private val adapter: ImageAdapter) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ) : Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.adapterPosition + adapter.delay.removeAt(position) + items.removeAt(position) + adapter.notifyDataSetChanged() + adapter.listeners.forEachIndexed { index, listener -> + if (index >= position) + listener.position = index + } + } + + override fun isItemViewSwipeEnabled() = true + } +} + diff --git a/app-test/src/main/java/oupson/apngcreator/MainActivity.kt b/app-test/src/main/java/oupson/apngcreator/activities/MainActivity.kt similarity index 79% rename from app-test/src/main/java/oupson/apngcreator/MainActivity.kt rename to app-test/src/main/java/oupson/apngcreator/activities/MainActivity.kt index c8301fe..a98a580 100644 --- a/app-test/src/main/java/oupson/apngcreator/MainActivity.kt +++ b/app-test/src/main/java/oupson/apngcreator/activities/MainActivity.kt @@ -1,4 +1,4 @@ -package oupson.apngcreator +package oupson.apngcreator.activities import android.annotation.SuppressLint import android.os.Bundle @@ -13,10 +13,15 @@ import com.google.android.material.shape.ShapeAppearanceModel import com.google.android.material.shape.ShapePath import kotlinx.android.synthetic.main.activity_main.* import org.jetbrains.anko.startActivity +import oupson.apngcreator.R +import oupson.apngcreator.fragments.ApngDecoderFragment +import oupson.apngcreator.fragments.JavaFragment +import oupson.apngcreator.fragments.KotlinFragment class MainActivity : AppCompatActivity() { companion object { + @Suppress("unused") private const val TAG = "MainActivity" } @@ -34,7 +39,10 @@ class MainActivity : AppCompatActivity() { startActivity() } - val drawerToggle = ActionBarDrawerToggle(this, drawer_layout, bottomAppBar, R.string.open, R.string.close) + val drawerToggle = ActionBarDrawerToggle(this, drawer_layout, bottomAppBar, + R.string.open, + R.string.close + ) drawer_layout.addDrawerListener(drawerToggle) drawerToggle.syncState() @@ -45,7 +53,10 @@ class MainActivity : AppCompatActivity() { R.id.menu_kotlin_fragment -> { if (selected != 0) { supportFragmentManager.beginTransaction().apply { - replace(R.id.fragment_container, KotlinFragment.newInstance()) + replace( + R.id.fragment_container, + KotlinFragment.newInstance() + ) addToBackStack(null) }.commit() selected = 0 @@ -54,7 +65,10 @@ class MainActivity : AppCompatActivity() { R.id.menu_java_fragment -> { if (selected != 1) { supportFragmentManager.beginTransaction().apply { - replace(R.id.fragment_container, JavaFragment()) + replace( + R.id.fragment_container, + JavaFragment() + ) addToBackStack(null) }.commit() selected = 1 @@ -63,7 +77,10 @@ class MainActivity : AppCompatActivity() { R.id.menu_apng_decoder_fragment -> { if (selected != 2) { supportFragmentManager.beginTransaction().apply { - replace(R.id.fragment_container, ApngDecoderFragment.newInstance()) + replace( + R.id.fragment_container, + ApngDecoderFragment.newInstance() + ) addToBackStack(null) }.commit() selected = 2 @@ -80,21 +97,29 @@ class MainActivity : AppCompatActivity() { when(intent.getStringExtra("fragment")) { "kotlin" -> { supportFragmentManager.beginTransaction().apply { - add(R.id.fragment_container, KotlinFragment.newInstance(), "KotlinFragment") + add( + R.id.fragment_container, + KotlinFragment.newInstance(), "KotlinFragment") }.commit() navigationView.setCheckedItem(R.id.menu_kotlin_fragment) selected = 0 } "java" -> { supportFragmentManager.beginTransaction().apply { - add(R.id.fragment_container, JavaFragment()) + add( + R.id.fragment_container, + JavaFragment() + ) }.commit() navigationView.setCheckedItem(R.id.menu_java_fragment) selected = 1 } "apng_decoder" -> { supportFragmentManager.beginTransaction().apply { - add(R.id.fragment_container, ApngDecoderFragment.newInstance()) + add( + R.id.fragment_container, + ApngDecoderFragment.newInstance() + ) }.commit() navigationView.setCheckedItem(R.id.menu_apng_decoder_fragment) selected = 2 @@ -102,7 +127,9 @@ class MainActivity : AppCompatActivity() { } } else { supportFragmentManager.beginTransaction().apply { - add(R.id.fragment_container, KotlinFragment.newInstance(), "KotlinFragment") + add( + R.id.fragment_container, + KotlinFragment.newInstance(), "KotlinFragment") }.commit() navigationView.setCheckedItem(R.id.menu_kotlin_fragment) } diff --git a/app-test/src/main/java/oupson/apngcreator/ViewerActivity.kt b/app-test/src/main/java/oupson/apngcreator/activities/ViewerActivity.kt similarity index 92% rename from app-test/src/main/java/oupson/apngcreator/ViewerActivity.kt rename to app-test/src/main/java/oupson/apngcreator/activities/ViewerActivity.kt index ca2359f..b299439 100644 --- a/app-test/src/main/java/oupson/apngcreator/ViewerActivity.kt +++ b/app-test/src/main/java/oupson/apngcreator/activities/ViewerActivity.kt @@ -1,4 +1,4 @@ -package oupson.apngcreator +package oupson.apngcreator.activities import android.Manifest import android.content.pm.PackageManager @@ -11,8 +11,9 @@ import kotlinx.android.synthetic.main.activity_viewer.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import oupson.apng.ApngDecoder import oupson.apng.CustomAnimationDrawable -import oupson.apng.ExperimentalApngDecoder +import oupson.apngcreator.R class ViewerActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -43,7 +44,7 @@ class ViewerActivity : AppCompatActivity() { val uri = intent.data ?: return GlobalScope.launch(Dispatchers.IO) { //val animator = imageView.loadApng(uri, null) - val drawable = ExperimentalApngDecoder.decodeApng(this@ViewerActivity, uri) + val drawable = ApngDecoder.decodeApng(this@ViewerActivity, uri) GlobalScope.launch(Dispatchers.Main) { viewerImageView.setImageDrawable(drawable) if (drawable is CustomAnimationDrawable) diff --git a/app-test/src/main/java/oupson/apngcreator/adapter/AnkoAdapter.kt b/app-test/src/main/java/oupson/apngcreator/adapter/AnkoAdapter.kt deleted file mode 100644 index 1ce7906..0000000 --- a/app-test/src/main/java/oupson/apngcreator/adapter/AnkoAdapter.kt +++ /dev/null @@ -1,29 +0,0 @@ -package oupson.apngcreator.adapter - -import android.content.Context -import android.view.View -import android.view.ViewGroup -import android.widget.BaseAdapter - -class AnkoAdapter(itemFactory: () -> List, - val viewFactory: Context.(index: Int, items: List, view: View?) -> View -): BaseAdapter() { - @Suppress("MemberVisibilityCanBePrivate") - val items: List by lazy { itemFactory() } - - override fun getView(index: Int, view: View?, viewGroup: ViewGroup?): View { - return viewGroup!!.context.viewFactory(index, items, view) - } - - override fun getCount(): Int { - return items.size - } - - override fun getItem(index: Int): T { - return items[index] - } - - override fun getItemId(index: Int): Long { - return (items[index] as Any).hashCode().toLong() + (index.toLong() * Int.MAX_VALUE) - } -} \ No newline at end of file diff --git a/app-test/src/main/java/oupson/apngcreator/adapter/ImageAdapter.kt b/app-test/src/main/java/oupson/apngcreator/adapter/ImageAdapter.kt new file mode 100644 index 0000000..34fbc47 --- /dev/null +++ b/app-test/src/main/java/oupson/apngcreator/adapter/ImageAdapter.kt @@ -0,0 +1,72 @@ +package oupson.apngcreator.adapter + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.textfield.TextInputEditText +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import oupson.apngcreator.R + +class ImageAdapter(private val context : Context, private val list : List) : RecyclerView.Adapter() { + val delay : ArrayList = arrayListOf() + val listeners : ArrayList = arrayListOf() + inner class Listener : TextWatcher { + var position : Int = -1 + override fun afterTextChanged(s: Editable?) {} + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + if (position > -1) + delay[position] = s?.toString() ?: "" + } + } + + inner class ImageHolder(view : View) : RecyclerView.ViewHolder(view) { + val imageView = view.findViewById(R.id.listImageView) + val textDelay = view.findViewById(R.id.textDelay) + val listener = Listener() + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageHolder { + val inflater = LayoutInflater.from(parent.context) + return ImageHolder(inflater.inflate(R.layout.list_image, parent, false)) + } + + override fun onBindViewHolder(holder: ImageHolder, position: Int) { + if (delay.size <= position) + delay.add("1000") + holder.textDelay?.addTextChangedListener(holder.listener.also{ + it.position = position + listeners.add(position, it) + }) + GlobalScope.launch(Dispatchers.IO) { + val inputStream = context.contentResolver.openInputStream(list[position]) + val btm = BitmapFactory.decodeStream(inputStream, null, BitmapFactory.Options().apply { + inPreferredConfig = Bitmap.Config.RGB_565 + }) + inputStream?.close() + withContext(Dispatchers.Main) { + holder.imageView?.setImageBitmap(btm) + } + } + } + + override fun onViewDetachedFromWindow(holder: ImageHolder) { + super.onViewDetachedFromWindow(holder) + holder.textDelay?.removeTextChangedListener(holder.listener) + listeners.remove(holder.listener) + } + + override fun getItemCount(): Int = list.count() + +} \ No newline at end of file diff --git a/app-test/src/main/java/oupson/apngcreator/ApngDecoderFragment.kt b/app-test/src/main/java/oupson/apngcreator/fragments/ApngDecoderFragment.kt similarity index 81% rename from app-test/src/main/java/oupson/apngcreator/ApngDecoderFragment.kt rename to app-test/src/main/java/oupson/apngcreator/fragments/ApngDecoderFragment.kt index c2e1979..efd8d6d 100644 --- a/app-test/src/main/java/oupson/apngcreator/ApngDecoderFragment.kt +++ b/app-test/src/main/java/oupson/apngcreator/fragments/ApngDecoderFragment.kt @@ -1,4 +1,4 @@ -package oupson.apngcreator +package oupson.apngcreator.fragments import android.graphics.drawable.Drawable @@ -9,7 +9,9 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.fragment.app.Fragment -import oupson.apng.ExperimentalApngDecoder +import oupson.apng.ApngDecoder +import oupson.apngcreator.BuildConfig +import oupson.apngcreator.R import java.net.URL class ApngDecoderFragment : Fragment() { @@ -30,11 +32,11 @@ class ApngDecoderFragment : Fragment() { val imageView : ImageView = view.findViewById(R.id.apngDecoderImageView) ?: return view if (context != null) { - ExperimentalApngDecoder.decodeApngAsyncInto( + ApngDecoder.decodeApngAsyncInto( this.context!!, - URL("http://littlesvr.ca/apng/images/GenevaDrive.png"), + URL("https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png"), imageView, - callback = object : ExperimentalApngDecoder.Callback { + callback = object : ApngDecoder.Callback { override fun onSuccess(drawable: Drawable) { if (BuildConfig.DEBUG) Log.i(TAG, "onSuccess()") diff --git a/app-test/src/main/java/oupson/apngcreator/JavaFragment.java b/app-test/src/main/java/oupson/apngcreator/fragments/JavaFragment.java similarity index 89% rename from app-test/src/main/java/oupson/apngcreator/JavaFragment.java rename to app-test/src/main/java/oupson/apngcreator/fragments/JavaFragment.java index 5eb91a7..eb83314 100644 --- a/app-test/src/main/java/oupson/apngcreator/JavaFragment.java +++ b/app-test/src/main/java/oupson/apngcreator/fragments/JavaFragment.java @@ -1,4 +1,4 @@ -package oupson.apngcreator; +package oupson.apngcreator.fragments; import android.content.Context; @@ -14,7 +14,8 @@ import androidx.fragment.app.Fragment; import org.jetbrains.annotations.NotNull; -import oupson.apng.ExperimentalApngDecoder; +import oupson.apng.ApngDecoder; +import oupson.apngcreator.R; public class JavaFragment extends Fragment { @@ -45,7 +46,7 @@ public class JavaFragment extends Fragment { return Unit.INSTANCE; }); */ - ExperimentalApngDecoder.decodeApngAsyncInto(context, imageUrl, imageView, 1f, new ExperimentalApngDecoder.Callback() { + ApngDecoder.decodeApngAsyncInto(context, imageUrl, imageView, 1f, new ApngDecoder.Callback() { @Override public void onSuccess(@NotNull Drawable drawable) { Log.i(TAG, "Success"); diff --git a/app-test/src/main/java/oupson/apngcreator/KotlinFragment.kt b/app-test/src/main/java/oupson/apngcreator/fragments/KotlinFragment.kt similarity index 95% rename from app-test/src/main/java/oupson/apngcreator/KotlinFragment.kt rename to app-test/src/main/java/oupson/apngcreator/fragments/KotlinFragment.kt index 1ae692d..c15a5e6 100644 --- a/app-test/src/main/java/oupson/apngcreator/KotlinFragment.kt +++ b/app-test/src/main/java/oupson/apngcreator/fragments/KotlinFragment.kt @@ -1,4 +1,4 @@ -package oupson.apngcreator +package oupson.apngcreator.fragments import android.os.Bundle @@ -13,6 +13,8 @@ import androidx.fragment.app.Fragment import com.squareup.picasso.Picasso import oupson.apng.ApngAnimator import oupson.apng.loadApng +import oupson.apngcreator.BuildConfig +import oupson.apngcreator.R class KotlinFragment : Fragment() { @@ -102,9 +104,9 @@ class KotlinFragment : Fragment() { if (BuildConfig.DEBUG) Log.i(TAG, "onPause()") - // animator = null + animator = null normalImageView?.setImageDrawable(null) - // apngImageView?.setImageDrawable(null) + apngImageView?.setImageDrawable(null) playButton?.setOnClickListener(null) pauseButton?.setOnClickListener(null) diff --git a/app-test/src/main/java/oupson/apngcreator/views/SquareImageView.kt b/app-test/src/main/java/oupson/apngcreator/views/SquareImageView.kt new file mode 100644 index 0000000..232609a --- /dev/null +++ b/app-test/src/main/java/oupson/apngcreator/views/SquareImageView.kt @@ -0,0 +1,21 @@ +package oupson.apngcreator.views + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatImageView + +class SquareImageView : AppCompatImageView { + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super( + context, + attrs, + defStyle + ) + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val height : Int = measuredHeight + setMeasuredDimension(height, height) + } +} \ No newline at end of file diff --git a/app-test/src/main/res/drawable/ic_play_arrow_black_24dp.xml b/app-test/src/main/res/drawable/ic_play_arrow_white_24dp.xml similarity index 88% rename from app-test/src/main/res/drawable/ic_play_arrow_black_24dp.xml rename to app-test/src/main/res/drawable/ic_play_arrow_white_24dp.xml index 1a1c9f2..1edbfbb 100644 --- a/app-test/src/main/res/drawable/ic_play_arrow_black_24dp.xml +++ b/app-test/src/main/res/drawable/ic_play_arrow_white_24dp.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/app-test/src/main/res/layout/activity_creator.xml b/app-test/src/main/res/layout/activity_creator.xml index b1a8bea..6e5e5b4 100644 --- a/app-test/src/main/res/layout/activity_creator.xml +++ b/app-test/src/main/res/layout/activity_creator.xml @@ -1,6 +1,31 @@ - - \ No newline at end of file + + + + + + \ No newline at end of file diff --git a/app-test/src/main/res/layout/activity_main.xml b/app-test/src/main/res/layout/activity_main.xml index 5e36603..6f20fb4 100644 --- a/app-test/src/main/res/layout/activity_main.xml +++ b/app-test/src/main/res/layout/activity_main.xml @@ -7,8 +7,7 @@ android:id="@+id/drawer_layout"> + android:layout_height="match_parent"> + android:layout_height="match_parent"> + tools:context=".fragments.ApngDecoderFragment"> + tools:context=".fragments.JavaFragment"> + android:layout_height="match_parent"> + app:layout_constraintTop_toTopOf="parent" + android:contentDescription="@string/description_viewer_imageView"/> + app:layout_constraintTop_toBottomOf="@id/ApngImageView" + android:contentDescription="@string/description_viewer_imageView" /> + + + + + + + + + \ No newline at end of file diff --git a/app-test/src/main/res/menu/creator_menu.xml b/app-test/src/main/res/menu/creator_menu.xml new file mode 100644 index 0000000..4b1f230 --- /dev/null +++ b/app-test/src/main/res/menu/creator_menu.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app-test/src/main/res/values-night/bools.xml b/app-test/src/main/res/values-night/bools.xml index 1750088..9cf91a4 100644 --- a/app-test/src/main/res/values-night/bools.xml +++ b/app-test/src/main/res/values-night/bools.xml @@ -1,4 +1,5 @@ false + true \ No newline at end of file diff --git a/app-test/src/main/res/values-night/colors.xml b/app-test/src/main/res/values-night/colors.xml index beb3633..5aadc71 100644 --- a/app-test/src/main/res/values-night/colors.xml +++ b/app-test/src/main/res/values-night/colors.xml @@ -6,5 +6,5 @@ #000 - #fff + #000 diff --git a/app-test/src/main/res/values/bools.xml b/app-test/src/main/res/values/bools.xml index c1210b7..7040b9b 100644 --- a/app-test/src/main/res/values/bools.xml +++ b/app-test/src/main/res/values/bools.xml @@ -1,4 +1,5 @@ true + false \ No newline at end of file diff --git a/app-test/src/main/res/values/strings.xml b/app-test/src/main/res/values/strings.xml index 2b8fe23..ce462dc 100644 --- a/app-test/src/main/res/values/strings.xml +++ b/app-test/src/main/res/values/strings.xml @@ -1,10 +1,6 @@ APNGCreator - Create APNG - Java Activity - An ImageView with an APNG - Loaded Image Play @@ -18,7 +14,5 @@ open close - - - Hello blank fragment + Delay (ms) diff --git a/app-test/src/main/res/values/styles.xml b/app-test/src/main/res/values/styles.xml index 5d8ea12..ea71a32 100644 --- a/app-test/src/main/res/values/styles.xml +++ b/app-test/src/main/res/values/styles.xml @@ -9,8 +9,11 @@ @color/text @color/text + @color/background + @bool/is_theme_light @color/colorPrimary + @bool/nav_bar_light