diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml index 60a7e8e..abf6a95 100644 --- a/.idea/assetWizardSettings.xml +++ b/.idea/assetWizardSettings.xml @@ -18,7 +18,7 @@ @@ -29,8 +29,8 @@ diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 52a3bf1..746bc38 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt b/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt index 868fa02..2404c77 100644 --- a/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt +++ b/apng_library/src/main/java/oupson/apng/APNGDisassembler.kt @@ -128,8 +128,9 @@ class APNGDisassembler { val crc = CRC32() crc.update(byteArray.copyOfRange(i, byteArray.size - 4)) if (chunkCRC == crc.value.toInt()) { - when (byteArray.copyOfRange(i, i + 4).contentToString()) { - Utils.fcTL -> { + val name= byteArray.copyOfRange(i, i + 4) + when { + name.contentEquals(Utils.fcTL) -> { if (png == null) { cover?.let { it.addAll(to4Bytes(0).asList()) @@ -198,7 +199,7 @@ class APNGDisassembler { } } } - Utils.IEND -> { + name.contentEquals(Utils.IEND) -> { if (isApng) { png?.addAll(to4Bytes(0).asList()) // Add IEND @@ -235,7 +236,7 @@ class APNGDisassembler { apng.isApng = false } } - Utils.IDAT -> { + name.contentEquals(Utils.IDAT) -> { if (png == null) { if (cover == null) { cover = ArrayList() @@ -267,7 +268,7 @@ class APNGDisassembler { png?.addAll(to4Bytes(crC32.value.toInt()).asList()) } } - Utils.fdAT -> { + name.contentEquals(Utils.fdAT) -> { // Find the chunk length val bodySize = parseLength(byteArray.copyOfRange(i - 4, i)) png?.addAll(to4Bytes(bodySize - 4).asList()) @@ -280,18 +281,18 @@ class APNGDisassembler { png?.addAll(body) png?.addAll(to4Bytes(crC32.value.toInt()).asList()) } - Utils.plte -> { + name.contentEquals(Utils.plte) -> { plte = byteArray } - Utils.tnrs -> { + name.contentEquals(Utils.tnrs) -> { tnrs = byteArray } - Utils.IHDR -> { + name.contentEquals(Utils.IHDR) -> { ihdr.parse(byteArray) maxWidth = ihdr.pngWidth maxHeight = ihdr.pngHeight } - Utils.acTL -> { + name.contentEquals(Utils.acTL) -> { isApng = true } } diff --git a/apng_library/src/main/java/oupson/apng/ExperimentalApngDecoder.kt b/apng_library/src/main/java/oupson/apng/ExperimentalApngDecoder.kt index 01f9460..a53aa1f 100644 --- a/apng_library/src/main/java/oupson/apng/ExperimentalApngDecoder.kt +++ b/apng_library/src/main/java/oupson/apng/ExperimentalApngDecoder.kt @@ -41,6 +41,7 @@ class ExperimentalApngDecoder { * @param speed Optional parameter. */ @Suppress("MemberVisibilityCanBePrivate") + @JvmStatic fun decodeApng(inStream: InputStream, speed : Float = 1f) : Drawable { val inputStream = BufferedInputStream(inStream) val bytes = ByteArray(8) @@ -85,8 +86,9 @@ class ExperimentalApngDecoder { val crc = CRC32() crc.update(byteArray.copyOfRange(i, byteArray.size - 4)) if (chunkCRC == crc.value.toInt()) { - when (byteArray.copyOfRange(i, i + 4).contentToString()) { - Utils.fcTL -> { + val name = byteArray.copyOfRange(i, i + 4) + when { + name.contentEquals(Utils.fcTL) -> { if (png == null) { cover?.let { it.addAll(Utils.to4Bytes(0).asList()) @@ -184,7 +186,7 @@ class ExperimentalApngDecoder { } } } - Utils.IEND -> { + name.contentEquals(Utils.IEND) -> { if (isApng && png != null) { png.addAll(Utils.to4Bytes(0).asList()) // Add IEND @@ -239,7 +241,7 @@ class ExperimentalApngDecoder { } } } - Utils.IDAT -> { + name.contentEquals(Utils.IDAT) -> { if (png == null) { if (cover == null) { cover = ArrayList() @@ -275,7 +277,7 @@ class ExperimentalApngDecoder { png.addAll(Utils.to4Bytes(crC32.value.toInt()).asList()) } } - Utils.fdAT -> { + name.contentEquals(Utils.fdAT) -> { // Find the chunk length val bodySize = Utils.parseLength(byteArray.copyOfRange(i - 4, i)) png?.addAll(Utils.to4Bytes(bodySize - 4).asList()) @@ -288,19 +290,19 @@ class ExperimentalApngDecoder { png?.addAll(body) png?.addAll(Utils.to4Bytes(crC32.value.toInt()).asList()) } - Utils.plte -> { + name.contentEquals(Utils.plte) -> { plte = byteArray } - Utils.tnrs -> { + name.contentEquals(Utils.tnrs) -> { tnrs = byteArray } - Utils.IHDR -> { + name.contentEquals(Utils.IHDR) -> { ihdr.parse(byteArray) maxWidth = ihdr.pngWidth maxHeight =ihdr.pngHeight buffer = Bitmap.createBitmap(maxWidth, maxHeight, Bitmap.Config.ARGB_8888) } - Utils.acTL -> { + name.contentEquals(Utils.acTL) -> { isApng = true } } @@ -325,6 +327,7 @@ class ExperimentalApngDecoder { * @param speed Optional parameter. */ @Suppress("unused") + @JvmStatic fun decodeApng(file : File, speed: Float = 1f) : Drawable = decodeApng(FileInputStream(file), speed) /** @@ -333,6 +336,7 @@ class ExperimentalApngDecoder { * @param uri Uri to open. * @param speed Optional parameter. */ + @JvmStatic fun decodeApng(context : Context, uri : Uri, speed: Float = 1f) : Drawable { val inputStream = context.contentResolver.openInputStream(uri) ?: throw Exception("Failed to open InputStream, InputStream is null") @@ -346,6 +350,7 @@ class ExperimentalApngDecoder { * @param speed Optional parameter. */ @Suppress("unused") + @JvmStatic fun decodeApng(context : Context, @RawRes res : Int, speed: Float = 1f) : Drawable = decodeApng(context.resources.openRawResource(res), speed) /** @@ -354,6 +359,8 @@ class ExperimentalApngDecoder { * @param url URL to decode. * @param speed Optional parameter. */ + @Suppress("unused") + @JvmStatic suspend fun decodeApng(context : Context, url : URL, speed: Float = 1f) = withContext(Dispatchers.IO) { decodeApng(FileInputStream(Loader.load(context, url)), speed) } diff --git a/apng_library/src/main/java/oupson/apng/Frame.kt b/apng_library/src/main/java/oupson/apng/Frame.kt index 643d44a..bb11a5a 100644 --- a/apng_library/src/main/java/oupson/apng/Frame.kt +++ b/apng_library/src/main/java/oupson/apng/Frame.kt @@ -81,18 +81,16 @@ class Frame// Get width and height for image * @param byteArray The frame */ private fun parseChunk(byteArray: ByteArray) { - when(byteArray.copyOfRange(4, 8).contentToString()) { - IHDR -> { - ihdr = IHDR() - ihdr.parse(byteArray) - width = ihdr.pngWidth - height = ihdr.pngHeight - } - IDAT -> { - // Get IDAT Bytes - idat = IDAT() - idat.parse(byteArray) - } + val name = byteArray.copyOfRange(4, 8) + if (name.contentEquals(IHDR)) { + ihdr = IHDR() + ihdr.parse(byteArray) + width = ihdr.pngWidth + height = ihdr.pngHeight + } else if (name.contentEquals(IDAT)){ + // Get IDAT Bytes + idat = IDAT() + idat.parse(byteArray) } } } \ No newline at end of file diff --git a/apng_library/src/main/java/oupson/apng/Loader.kt b/apng_library/src/main/java/oupson/apng/Loader.kt index 587b35e..be2e3f6 100644 --- a/apng_library/src/main/java/oupson/apng/Loader.kt +++ b/apng_library/src/main/java/oupson/apng/Loader.kt @@ -16,7 +16,6 @@ class Loader { * @param url Url of the file to download * @return [ByteArray] of the file */ - @Suppress("RedundantSuspendModifier") @Throws(IOException::class) suspend fun load(context: Context, url: URL): File = withContext(Dispatchers.IO) { val currentDir = context.filesDir diff --git a/apng_library/src/main/java/oupson/apng/utils/Utils.kt b/apng_library/src/main/java/oupson/apng/utils/Utils.kt index 8ec1d62..d1af031 100644 --- a/apng_library/src/main/java/oupson/apng/utils/Utils.kt +++ b/apng_library/src/main/java/oupson/apng/utils/Utils.kt @@ -7,7 +7,11 @@ class Utils { * @return [Boolean] True if is a png */ fun isPng(byteArray: ByteArray): Boolean { - return byteArray.copyOfRange(0, 8).contentToString() == pngSignature.contentToString() + // return byteArray.copyOfRange(0, 8).contentToString() == pngSignature.contentToString() + return if (byteArray.size == 8) + byteArray.contentEquals(pngSignature) + else + byteArray.copyOfRange(0, 8).contentEquals(pngSignature) } /** @@ -146,13 +150,13 @@ class Utils { return lengthString.toLong(16).toInt() } - val fcTL : String by lazy { byteArrayOf(0x66, 0x63, 0x54, 0x4c).contentToString() } - val IEND : String by lazy { byteArrayOf(0x49, 0x45, 0x4e, 0x44).contentToString() } - val IDAT : String by lazy { byteArrayOf(0x49, 0x44, 0x41, 0x54).contentToString() } - val fdAT : String by lazy { byteArrayOf(0x66, 0x64, 0x41, 0x54).contentToString() } - val plte : String by lazy { byteArrayOf(0x50, 0x4c, 0x54, 0x45).contentToString() } - val tnrs : String by lazy { byteArrayOf(0x74, 0x52, 0x4e, 0x53).contentToString() } - val IHDR : String by lazy { byteArrayOf(0x49, 0x48, 0x44, 0x52).contentToString() } - val acTL : String by lazy { byteArrayOf(0x61, 0x63, 0x54, 0x4c).contentToString() } + val fcTL : ByteArray by lazy { byteArrayOf(0x66, 0x63, 0x54, 0x4c) } + val IEND : ByteArray by lazy { byteArrayOf(0x49, 0x45, 0x4e, 0x44) } + val IDAT : ByteArray by lazy { byteArrayOf(0x49, 0x44, 0x41, 0x54) } + val fdAT : ByteArray by lazy { byteArrayOf(0x66, 0x64, 0x41, 0x54) } + val plte : ByteArray by lazy { byteArrayOf(0x50, 0x4c, 0x54, 0x45) } + val tnrs : ByteArray by lazy { byteArrayOf(0x74, 0x52, 0x4e, 0x53) } + val IHDR : ByteArray by lazy { byteArrayOf(0x49, 0x48, 0x44, 0x52) } + val acTL : ByteArray by lazy { byteArrayOf(0x61, 0x63, 0x54, 0x4c) } } } \ No newline at end of file diff --git a/app-test/build.gradle b/app-test/build.gradle index bca1e56..706c1eb 100644 --- a/app-test/build.gradle +++ b/app-test/build.gradle @@ -36,6 +36,7 @@ dependencies { //noinspection GradleCompatible implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -44,7 +45,7 @@ dependencies { implementation project(":apng_library") // implementation fileTree(include: ['*.aar'], dir: 'libs') //implementation 'com.github.oupson:Kapng-Android:1.0.0' - implementation 'com.google.android.material:material:1.0.0' + implementation 'com.google.android.material:material:1.2.0-alpha04' implementation "org.jetbrains.anko:anko-appcompat-v7:$anko_version" implementation "org.jetbrains.anko:anko-design:$anko_version" implementation "org.jetbrains.anko:anko-constraint-layout:$anko_version" diff --git a/app-test/src/main/AndroidManifest.xml b/app-test/src/main/AndroidManifest.xml index bc76a72..b6115e5 100644 --- a/app-test/src/main/AndroidManifest.xml +++ b/app-test/src/main/AndroidManifest.xml @@ -16,9 +16,6 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - - @@ -27,7 +24,7 @@ diff --git a/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt b/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt index ee0a25d..8beb3be 100644 --- a/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt +++ b/app-test/src/main/java/oupson/apngcreator/CreatorActivity.kt @@ -23,6 +23,7 @@ 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 @@ -112,11 +113,11 @@ class CreatorActivity : AppCompatActivity() { } class CreatorActivityLayout : AnkoComponent { - lateinit var listView : ListView - lateinit var addFrameButton : FloatingActionButton - lateinit var createButton : FloatingActionButton - lateinit var optimiseCheckBox : CheckBox - lateinit var toolbar : Toolbar + 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 @@ -124,57 +125,58 @@ class CreatorActivityLayout : AnkoComponent { id = View.generateViewId() backgroundColor = Color.WHITE appBarLayout { - toolbar = xToolbar { - id = View.generateViewId() + /**toolbar = xToolbar { + id = View.generateViewId() }.lparams { - width = matchParent - height = wrapContent + width = matchParent + height = wrapContent } - }.lparams { + }.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() } - }.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/JavaActivity.java b/app-test/src/main/java/oupson/apngcreator/JavaActivity.java deleted file mode 100644 index ed91b44..0000000 --- a/app-test/src/main/java/oupson/apngcreator/JavaActivity.java +++ /dev/null @@ -1,30 +0,0 @@ -package oupson.apngcreator; - -import android.os.Bundle; -import android.util.Log; -import android.widget.ImageView; -import androidx.appcompat.app.AppCompatActivity; -import kotlin.Unit; -import oupson.apng.ApngAnimator; -import oupson.apng.ApngAnimatorKt; -public class JavaActivity extends AppCompatActivity { - private static final String TAG = "JavaActivity"; - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_java); - String imageUrl = "https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png"; - ImageView image = findViewById(R.id.javaImageView); - ApngAnimator a = ApngAnimatorKt.loadApng(image, imageUrl); - a.onLoaded((animator) -> { - animator.setOnFrameChangeLister((index) -> { - if (index == 0) { - Log.i(TAG, "Loop"); - } - return Unit.INSTANCE; - }); - return Unit.INSTANCE; - }); - - } -} diff --git a/app-test/src/main/java/oupson/apngcreator/JavaFragment.java b/app-test/src/main/java/oupson/apngcreator/JavaFragment.java new file mode 100644 index 0000000..76fe2d3 --- /dev/null +++ b/app-test/src/main/java/oupson/apngcreator/JavaFragment.java @@ -0,0 +1,43 @@ +package oupson.apngcreator; + + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.fragment.app.Fragment; + +import kotlin.Unit; +import oupson.apng.ApngAnimator; +import oupson.apng.ApngAnimatorKt; + + +public class JavaFragment extends Fragment { + private static final String TAG = "JavaActivity"; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + Log.i(TAG, "onCreateView()"); + View v = inflater.inflate(R.layout.fragment_java, container, false); + String imageUrl = "https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png"; + ImageView imageView = v.findViewById(R.id.javaImageView); + if (imageView != null) { + ApngAnimator a = ApngAnimatorKt.loadApng(imageView, imageUrl); + a.onLoaded((animator) -> { + animator.setOnFrameChangeLister((index) -> { + if (index == 0) { + Log.i(TAG, "Loop"); + } + return Unit.INSTANCE; + }); + return Unit.INSTANCE; + }); + } + return v; + } + +} diff --git a/app-test/src/main/java/oupson/apngcreator/KotlinFragment.kt b/app-test/src/main/java/oupson/apngcreator/KotlinFragment.kt new file mode 100644 index 0000000..1ae692d --- /dev/null +++ b/app-test/src/main/java/oupson/apngcreator/KotlinFragment.kt @@ -0,0 +1,120 @@ +package oupson.apngcreator + + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ImageView +import android.widget.SeekBar +import androidx.fragment.app.Fragment +import com.squareup.picasso.Picasso +import oupson.apng.ApngAnimator +import oupson.apng.loadApng + + +class KotlinFragment : Fragment() { + private var apngImageView : ImageView? = null + private var normalImageView : ImageView? = null + + private var pauseButton : Button? = null + private var playButton : Button? = null + + private var speedSeekBar : SeekBar? = null + + private var animator : ApngAnimator? = null + + private val imageUrls = arrayListOf( + "http://oupson.oupsman.fr/apng/bigApng.png", + "https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png", + "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg", + "http://orig06.deviantart.net/7812/f/2012/233/7/5/twilight_rapidash_shaded_and_animated_by_tamalesyatole-d5bz7hd.png", + "https://raw.githubusercontent.com/tinify/iMessage-Panda-sticker/master/StickerPackExtension/Stickers.xcstickers/Sticker%20Pack.stickerpack/panda.sticker/panda.png", + "file:///android_asset/image.png" + ) + private val selected = 4 + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + if (BuildConfig.DEBUG) + Log.i(TAG, "onCreateView()") + // Inflate the layout for this fragment + val view = inflater.inflate(R.layout.fragment_kotlin, container, false) + + apngImageView = view.findViewById(R.id.ApngImageView) + normalImageView = view.findViewById(R.id.NormalImageView) + + pauseButton = view.findViewById(R.id.PauseButton) + playButton = view.findViewById(R.id.PlayButton) + + speedSeekBar = view.findViewById(R.id.SpeedSeekBar) + + return view + } + + override fun onResume() { + super.onResume() + if (BuildConfig.DEBUG) + Log.i(TAG, "onResume()") + + playButton?.setOnClickListener { + animator?.play() + } + + pauseButton?.setOnClickListener { + animator?.pause() + } + + speedSeekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + if (seekBar != null) + animator?.speed = seekBar.progress.toFloat() / 100f + } + }) + + if (animator == null) { + animator = apngImageView?.loadApng(imageUrls[selected])?.apply { + onLoaded { + setOnFrameChangeLister { + // Log.e("app-test", "onLoop") + } + } + } + } + + Picasso.get().load(imageUrls[selected]).into(normalImageView) + } + + override fun onPause() { + super.onPause() + if (BuildConfig.DEBUG) + Log.i(TAG, "onPause()") + + // animator = null + normalImageView?.setImageDrawable(null) + // apngImageView?.setImageDrawable(null) + + playButton?.setOnClickListener(null) + pauseButton?.setOnClickListener(null) + speedSeekBar?.setOnSeekBarChangeListener(null) + } + + companion object { + private const val TAG = "KotlinFragment" + @JvmStatic + fun newInstance() = + KotlinFragment() + } +} \ No newline at end of file diff --git a/app-test/src/main/java/oupson/apngcreator/MainActivity.kt b/app-test/src/main/java/oupson/apngcreator/MainActivity.kt index ff2426a..71bb185 100644 --- a/app-test/src/main/java/oupson/apngcreator/MainActivity.kt +++ b/app-test/src/main/java/oupson/apngcreator/MainActivity.kt @@ -1,188 +1,131 @@ package oupson.apngcreator -import android.graphics.Color +import android.annotation.SuppressLint import android.os.Bundle -import android.view.Menu import android.view.MenuItem -import android.view.View -import android.view.ViewManager +import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity -import androidx.constraintlayout.widget.ConstraintLayout -import com.squareup.picasso.Picasso -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import org.jetbrains.anko.* -import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder -import org.jetbrains.anko.constraint.layout.applyConstraintSet -import org.jetbrains.anko.constraint.layout.constraintLayout -import org.jetbrains.anko.constraint.layout.matchConstraint -import org.jetbrains.anko.custom.ankoView -import org.jetbrains.anko.design.appBarLayout -import org.jetbrains.anko.sdk27.coroutines.onClick -import org.jetbrains.anko.sdk27.coroutines.onSeekBarChangeListener -import oupson.apng.ApngAnimator -import oupson.apng.CustomAnimationDrawable -import oupson.apng.ExperimentalApngDecoder -import java.net.URL +import androidx.core.view.GravityCompat +import com.google.android.material.bottomappbar.BottomAppBarTopEdgeTreatment +import com.google.android.material.shape.CutCornerTreatment +import com.google.android.material.shape.MaterialShapeDrawable +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 + -// TODO REMOVE ANKO -fun ViewManager.xToolbar(init : androidx.appcompat.widget.Toolbar.() -> Unit) = ankoView({androidx.appcompat.widget.Toolbar(it)}, 0, init) class MainActivity : AppCompatActivity() { - private lateinit var animator: ApngAnimator - private lateinit var tool : androidx.appcompat.widget.Toolbar - // val imageUrl = "http://oupson.oupsman.fr/apng/bigApng.png" - private val imageUrl = "https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png" - //private val imageUrl = "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg" - // val imageUrl = "http://orig06.deviantart.net/7812/f/2012/233/7/5/twilight_rapidash_shaded_and_animated_by_tamalesyatole-d5bz7hd.png" - // val imageUrl = "https://raw.githubusercontent.com/tinify/iMessage-Panda-sticker/master/StickerPackExtension/Stickers.xcstickers/Sticker%20Pack.stickerpack/panda.sticker/panda.png" - // val imageUrl = "file:///android_asset/image.png" + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - verticalLayout { - verticalLayout { - appBarLayout { - tool = xToolbar { - id = View.generateViewId() - }.lparams { - width = matchParent - height = wrapContent - } - }.lparams { - width = matchParent - height = wrapContent - bottomMargin = 1 - } - }.lparams { - width = matchParent - height = wrapContent - } - constraintLayout { - backgroundColor = Color.WHITE - val pauseButton = button("pause") { - backgroundColor = Color.WHITE - id = View.generateViewId() - onClick { - animator.pause() - } - }.lparams( - width = wrapContent, - height = wrapContent - ) - val playButton = button("play") { - backgroundColor = Color.WHITE - id = View.generateViewId() - onClick { - animator.play() - } - }.lparams( - width = wrapContent, - height = wrapContent - ) - val seekBar = seekBar { - id = View.generateViewId() - max = 200 - progress = 100 - onSeekBarChangeListener { - onProgressChanged { _, _, _ -> } - onStartTrackingTouch { } - onStopTrackingTouch { seekBar -> - animator.speed = (seekBar?.progress?.toFloat() ?: 100f) / 100f - } - } - }.lparams( - width = matchConstraint, - height = wrapContent - ) - val imageView2 = imageView { - id = View.generateViewId() - Picasso.get().load(imageUrl).into(this) - }.lparams( - width = matchConstraint, - height = matchConstraint - ) - val imageView = imageView { - id = View.generateViewId() - GlobalScope.launch(Dispatchers.IO) { - val drawable = ExperimentalApngDecoder.decodeApng(this@MainActivity, URL(imageUrl)) - GlobalScope.launch(Dispatchers.Main) { - this@imageView.setImageDrawable(drawable) - if (drawable is CustomAnimationDrawable) - drawable.start() - } - } + setContentView(R.layout.activity_main) - /** - animator = this.loadApng(imageUrl).apply { - onLoaded { - setOnFrameChangeLister { - // Log.e("app-test", "onLoop") - } - } - } - */ - }.lparams( - width = matchConstraint, - height = matchConstraint - ) - applyConstraintSet { - pauseButton { - connect( - ConstraintSetBuilder.Side.BOTTOM to ConstraintSetBuilder.Side.TOP of seekBar margin dip(8), - ConstraintSetBuilder.Side.END to ConstraintSetBuilder.Side.END of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8) - ) - } - playButton { - connect( - ConstraintSetBuilder.Side.BOTTOM to ConstraintSetBuilder.Side.TOP of seekBar margin dip(8), - ConstraintSetBuilder.Side.START to ConstraintSetBuilder.Side.START of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8) - ) - } - seekBar { - connect( - ConstraintSetBuilder.Side.BOTTOM to ConstraintSetBuilder.Side.BOTTOM of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8), - ConstraintSetBuilder.Side.END to ConstraintSetBuilder.Side.END of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8), - ConstraintSetBuilder.Side.START to ConstraintSetBuilder.Side.START of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8) - ) - } - imageView2 { - connect( - ConstraintSetBuilder.Side.BOTTOM to ConstraintSetBuilder.Side.TOP of playButton margin dip(8), - ConstraintSetBuilder.Side.END to ConstraintSetBuilder.Side.END of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8), - ConstraintSetBuilder.Side.START to ConstraintSetBuilder.Side.START of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8), - ConstraintSetBuilder.Side.TOP to ConstraintSetBuilder.Side.BOTTOM of imageView - ) - } - imageView { - connect( - ConstraintSetBuilder.Side.BOTTOM to ConstraintSetBuilder.Side.TOP of imageView2 margin dip(8), - ConstraintSetBuilder.Side.END to ConstraintSetBuilder.Side.END of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8), - ConstraintSetBuilder.Side.START to ConstraintSetBuilder.Side.START of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8), - ConstraintSetBuilder.Side.TOP to ConstraintSetBuilder.Side.TOP of ConstraintLayout.LayoutParams.PARENT_ID margin dip(8) - ) + setSupportActionBar(bottomAppBar) + + setUpBottomAppBarShapeAppearance() + + fabCreate.setOnClickListener { + startActivity() + } + + val drawerToggle = ActionBarDrawerToggle(this, drawer_layout, bottomAppBar, R.string.open, R.string.close) + drawer_layout.addDrawerListener(drawerToggle) + drawerToggle.syncState() + + var selected = 0 + + navigationView.setNavigationItemSelectedListener { menuItem : MenuItem -> + when(menuItem.itemId) { + R.id.menu_kotlin_activity -> { + if (selected != 0) { + supportFragmentManager.beginTransaction().apply { + replace(R.id.fragment_container, KotlinFragment.newInstance()) + addToBackStack(null) + }.commit() + selected = 0 + } + } + R.id.menu_java_activity -> { + if (selected != 1) { + supportFragmentManager.beginTransaction().apply { + replace(R.id.fragment_container, JavaFragment()) + addToBackStack(null) + }.commit() + selected = 1 } } - }.lparams { - width = matchParent - height = matchParent } + + drawer_layout.closeDrawer(GravityCompat.START) + + return@setNavigationItemSelectedListener true } - setSupportActionBar(tool) + + supportFragmentManager.beginTransaction().apply { + add(R.id.fragment_container, KotlinFragment.newInstance(), "KotlinFragment") + }.commit() + + + navigationView.setCheckedItem(R.id.menu_kotlin_activity) } - override fun onCreateOptionsMenu(menu: Menu?): Boolean { - val inflater = menuInflater - inflater.inflate(R.menu.main_menu, menu) - return true + private fun setUpBottomAppBarShapeAppearance() { + val fabShapeAppearanceModel: ShapeAppearanceModel = fabCreate.shapeAppearanceModel + val cutCornersFab = + (fabShapeAppearanceModel.bottomLeftCorner is CutCornerTreatment + && fabShapeAppearanceModel.bottomRightCorner is CutCornerTreatment) + val topEdge = + if (cutCornersFab) BottomAppBarCutCornersTopEdge( + bottomAppBar.fabCradleMargin, + bottomAppBar.fabCradleRoundedCornerRadius, + bottomAppBar.cradleVerticalOffset + ) else BottomAppBarTopEdgeTreatment( + bottomAppBar.fabCradleMargin, + bottomAppBar.fabCradleRoundedCornerRadius, + bottomAppBar.cradleVerticalOffset + ) + val babBackground = bottomAppBar.background as MaterialShapeDrawable + babBackground.shapeAppearanceModel = + babBackground.shapeAppearanceModel.toBuilder().setTopEdge(topEdge).build() } - override fun onOptionsItemSelected(item: MenuItem?): Boolean { - when (item!!.itemId) { - R.id.action_open_create_activity -> startActivity() - R.id.action_open_java_activity -> startActivity() + + inner class BottomAppBarCutCornersTopEdge( + private val fabMargin: Float, + roundedCornerRadius: Float, + private val cradleVerticalOffset: Float + ) : + BottomAppBarTopEdgeTreatment(fabMargin, roundedCornerRadius, cradleVerticalOffset) { + @SuppressLint("RestrictedApi") + override fun getEdgePath( + length: Float, + center: Float, + interpolation: Float, + shapePath: ShapePath + ) { + val fabDiameter = fabDiameter + if (fabDiameter == 0f) { + shapePath.lineTo(length, 0f) + return + } + val diamondSize = fabDiameter / 2f + val middle = center + horizontalOffset + val verticalOffsetRatio = cradleVerticalOffset / diamondSize + if (verticalOffsetRatio >= 1.0f) { + shapePath.lineTo(length, 0f) + return + } + shapePath.lineTo(middle - (fabMargin + diamondSize - cradleVerticalOffset), 0f) + shapePath.lineTo( + middle, + (diamondSize - cradleVerticalOffset + fabMargin) * interpolation + ) + shapePath.lineTo(middle + (fabMargin + diamondSize - cradleVerticalOffset), 0f) + shapePath.lineTo(length, 0f) } - return super.onOptionsItemSelected(item) + } } diff --git a/app-test/src/main/java/oupson/apngcreator/Main2Activity.kt b/app-test/src/main/java/oupson/apngcreator/ViewerActivity.kt similarity index 60% rename from app-test/src/main/java/oupson/apngcreator/Main2Activity.kt rename to app-test/src/main/java/oupson/apngcreator/ViewerActivity.kt index d502b43..ca2359f 100644 --- a/app-test/src/main/java/oupson/apngcreator/Main2Activity.kt +++ b/app-test/src/main/java/oupson/apngcreator/ViewerActivity.kt @@ -2,32 +2,23 @@ package oupson.apngcreator import android.Manifest import android.content.pm.PackageManager -import android.graphics.Color import android.os.Bundle import android.view.View -import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import org.jetbrains.anko.backgroundColor -import org.jetbrains.anko.imageView -import org.jetbrains.anko.matchParent -import org.jetbrains.anko.verticalLayout +import kotlinx.android.synthetic.main.activity_viewer.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import oupson.apng.CustomAnimationDrawable import oupson.apng.ExperimentalApngDecoder -class Main2Activity : AppCompatActivity() { - private lateinit var imageView : ImageView +class ViewerActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setContentView(R.layout.activity_viewer) - verticalLayout { - imageView = imageView().lparams { - width = matchParent - height = matchParent - } - backgroundColor = Color.parseColor("#323232") - } window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN @@ -50,26 +41,15 @@ class Main2Activity : AppCompatActivity() { private fun load() { val uri = intent.data ?: return - //val animator = imageView.loadApng(uri, null) - val drawable = ExperimentalApngDecoder.decodeApng(this, uri) - imageView.setImageDrawable(drawable) - if (drawable is CustomAnimationDrawable) - drawable.start() - /** - imageView.onClick { - try { - if (animator.isApng) { - if (animator.isPlaying) { - animator.pause() - } else { - animator.play() - } - } - } catch (e: Exception) { - e.printStackTrace() + GlobalScope.launch(Dispatchers.IO) { + //val animator = imageView.loadApng(uri, null) + val drawable = ExperimentalApngDecoder.decodeApng(this@ViewerActivity, uri) + GlobalScope.launch(Dispatchers.Main) { + viewerImageView.setImageDrawable(drawable) + if (drawable is CustomAnimationDrawable) + drawable.start() } } - */ } override fun onRequestPermissionsResult(requestCode: Int, diff --git a/app-test/src/main/res/color/drawer_item.xml b/app-test/src/main/res/color/drawer_item.xml new file mode 100644 index 0000000..9b4dbb0 --- /dev/null +++ b/app-test/src/main/res/color/drawer_item.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app-test/src/main/res/drawable/ic_create_white_24dp.xml b/app-test/src/main/res/drawable/ic_create_white_24dp.xml new file mode 100644 index 0000000..46462b5 --- /dev/null +++ b/app-test/src/main/res/drawable/ic_create_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app-test/src/main/res/drawable/ic_java.xml b/app-test/src/main/res/drawable/ic_java.xml new file mode 100644 index 0000000..8c8d4a2 --- /dev/null +++ b/app-test/src/main/res/drawable/ic_java.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/app-test/src/main/res/drawable/ic_kotlin.xml b/app-test/src/main/res/drawable/ic_kotlin.xml new file mode 100644 index 0000000..ba43a68 --- /dev/null +++ b/app-test/src/main/res/drawable/ic_kotlin.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app-test/src/main/res/drawable/ic_menu_white_24dp.xml b/app-test/src/main/res/drawable/ic_menu_white_24dp.xml new file mode 100644 index 0000000..de103a6 --- /dev/null +++ b/app-test/src/main/res/drawable/ic_menu_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app-test/src/main/res/layout/activity_java.xml b/app-test/src/main/res/layout/activity_java.xml deleted file mode 100644 index 0a95e0e..0000000 --- a/app-test/src/main/res/layout/activity_java.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - \ 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 new file mode 100644 index 0000000..5e36603 --- /dev/null +++ b/app-test/src/main/res/layout/activity_main.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app-test/src/main/res/layout/activity_viewer.xml b/app-test/src/main/res/layout/activity_viewer.xml new file mode 100644 index 0000000..0ec4c0c --- /dev/null +++ b/app-test/src/main/res/layout/activity_viewer.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app-test/src/main/res/layout/fragment_java.xml b/app-test/src/main/res/layout/fragment_java.xml new file mode 100644 index 0000000..f11b925 --- /dev/null +++ b/app-test/src/main/res/layout/fragment_java.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/app-test/src/main/res/layout/fragment_kotlin.xml b/app-test/src/main/res/layout/fragment_kotlin.xml new file mode 100644 index 0000000..a8462a1 --- /dev/null +++ b/app-test/src/main/res/layout/fragment_kotlin.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + +