Work in creator activity and improvements in app
Working on apng decoder
This commit is contained in:
parent
4863dfb2e8
commit
acd55f6d5a
|
@ -17,6 +17,8 @@ import oupson.apng.utils.Utils.Companion.to4Bytes
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.zip.CRC32
|
import java.util.zip.CRC32
|
||||||
|
|
||||||
|
|
||||||
|
// TODO CREATE A BETTER CLASS
|
||||||
/**
|
/**
|
||||||
* Create an APNG file
|
* Create an APNG file
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -92,7 +92,7 @@ fun ImageView.loadApng(@RawRes res : Int, speed : Float? = null, apngAnimatorOpt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to play APNG
|
* 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?) {
|
class ApngAnimator(private val context: Context?) {
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
@ -112,6 +112,7 @@ class ApngAnimator(private val context: Context?) {
|
||||||
}
|
}
|
||||||
private var imageView: ImageView? = null
|
private var imageView: ImageView? = null
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
var anim: CustomAnimationDrawable? = null
|
var anim: CustomAnimationDrawable? = null
|
||||||
private var activeAnimation: CustomAnimationDrawable? = null
|
private var activeAnimation: CustomAnimationDrawable? = null
|
||||||
|
|
||||||
|
|
|
@ -24,16 +24,14 @@ import java.io.InputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.zip.CRC32
|
import java.util.zip.CRC32
|
||||||
|
|
||||||
// TODO DOC CODE
|
class ApngDecoder {
|
||||||
class ExperimentalApngDecoder {
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun onSuccess(drawable : Drawable)
|
fun onSuccess(drawable : Drawable)
|
||||||
fun onError(error : java.lang.Exception)
|
fun onError(error : java.lang.Exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// TODO Change TAG
|
private const val TAG = "ApngDecoder"
|
||||||
private const val TAG = "ExperimentalApngDecoder"
|
|
||||||
|
|
||||||
private val clearPaint : Paint by lazy {
|
private val clearPaint : Paint by lazy {
|
||||||
Paint().apply {
|
Paint().apply {
|
||||||
|
@ -378,7 +376,7 @@ class ExperimentalApngDecoder {
|
||||||
* @param file File to decode.
|
* @param file File to decode.
|
||||||
* @param imageView Image View.
|
* @param imageView Image View.
|
||||||
* @param speed Optional parameter.
|
* @param speed Optional parameter.
|
||||||
* @param callback [ExperimentalApngDecoder.Callback] to handle success and error
|
* @param callback [ApngDecoder.Callback] to handle success and error
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -406,7 +404,7 @@ class ExperimentalApngDecoder {
|
||||||
* @param uri Uri to load
|
* @param uri Uri to load
|
||||||
* @param imageView Image View.
|
* @param imageView Image View.
|
||||||
* @param speed Optional parameter.
|
* @param speed Optional parameter.
|
||||||
* @param callback [ExperimentalApngDecoder.Callback] to handle success and error
|
* @param callback [ApngDecoder.Callback] to handle success and error
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -435,7 +433,7 @@ class ExperimentalApngDecoder {
|
||||||
* @param res Raw resource to load
|
* @param res Raw resource to load
|
||||||
* @param imageView Image View.
|
* @param imageView Image View.
|
||||||
* @param speed Optional parameter.
|
* @param speed Optional parameter.
|
||||||
* @param callback [ExperimentalApngDecoder.Callback] to handle success and error
|
* @param callback [ApngDecoder.Callback] to handle success and error
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -464,7 +462,7 @@ class ExperimentalApngDecoder {
|
||||||
* @param url URL to load
|
* @param url URL to load
|
||||||
* @param imageView Image View.
|
* @param imageView Image View.
|
||||||
* @param speed Optional parameter.
|
* @param speed Optional parameter.
|
||||||
* @param callback [ExperimentalApngDecoder.Callback] to handle success and error
|
* @param callback [ApngDecoder.Callback] to handle success and error
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -492,7 +490,7 @@ class ExperimentalApngDecoder {
|
||||||
* @param string URL to load
|
* @param string URL to load
|
||||||
* @param imageView Image View.
|
* @param imageView Image View.
|
||||||
* @param speed Optional parameter.
|
* @param speed Optional parameter.
|
||||||
* @param callback [ExperimentalApngDecoder.Callback] to handle success and error
|
* @param callback [ApngDecoder.Callback] to handle success and error
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@JvmStatic
|
@JvmStatic
|
|
@ -5,6 +5,7 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
class Loader {
|
class Loader {
|
||||||
|
@ -15,7 +16,7 @@ class Loader {
|
||||||
* @param url Url of the file to download
|
* @param url Url of the file to download
|
||||||
* @return [ByteArray] of the file
|
* @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) =
|
suspend fun load(context: Context, url: URL) =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val currentDir = context.filesDir
|
val currentDir = context.filesDir
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity android:name=".MainActivity">
|
<activity android:name=".activities.MainActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ViewerActivity"
|
android:name=".activities.ViewerActivity"
|
||||||
android:label="APNG Viewer">
|
android:label="APNG Viewer">
|
||||||
<intent-filter tools:ignore="AppLinkUrlError">
|
<intent-filter tools:ignore="AppLinkUrlError">
|
||||||
<action android:name="android.intent.action.VIEW"/>
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
@ -36,8 +36,23 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".CreatorActivity"
|
android:name=".activities.CreatorActivity"
|
||||||
android:exported="true"/>
|
android:exported="true"
|
||||||
|
android:parentActivityName=".activities.MainActivity">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value=".activities.MainActivity" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.provider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/provider_paths"/>
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -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<Bitmap> = ArrayList()
|
|
||||||
private var bitmapAdapter : AnkoAdapter<Bitmap>? = 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<CreatorActivity> {
|
|
||||||
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<CreatorActivity>) = 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<Uri> = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package oupson.apngcreator
|
package oupson.apngcreator.activities
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -13,10 +13,15 @@ import com.google.android.material.shape.ShapeAppearanceModel
|
||||||
import com.google.android.material.shape.ShapePath
|
import com.google.android.material.shape.ShapePath
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import org.jetbrains.anko.startActivity
|
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() {
|
class MainActivity : AppCompatActivity() {
|
||||||
companion object {
|
companion object {
|
||||||
|
@Suppress("unused")
|
||||||
private const val TAG = "MainActivity"
|
private const val TAG = "MainActivity"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +39,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
startActivity<CreatorActivity>()
|
startActivity<CreatorActivity>()
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
drawer_layout.addDrawerListener(drawerToggle)
|
||||||
drawerToggle.syncState()
|
drawerToggle.syncState()
|
||||||
|
|
||||||
|
@ -45,7 +53,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
R.id.menu_kotlin_fragment -> {
|
R.id.menu_kotlin_fragment -> {
|
||||||
if (selected != 0) {
|
if (selected != 0) {
|
||||||
supportFragmentManager.beginTransaction().apply {
|
supportFragmentManager.beginTransaction().apply {
|
||||||
replace(R.id.fragment_container, KotlinFragment.newInstance())
|
replace(
|
||||||
|
R.id.fragment_container,
|
||||||
|
KotlinFragment.newInstance()
|
||||||
|
)
|
||||||
addToBackStack(null)
|
addToBackStack(null)
|
||||||
}.commit()
|
}.commit()
|
||||||
selected = 0
|
selected = 0
|
||||||
|
@ -54,7 +65,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
R.id.menu_java_fragment -> {
|
R.id.menu_java_fragment -> {
|
||||||
if (selected != 1) {
|
if (selected != 1) {
|
||||||
supportFragmentManager.beginTransaction().apply {
|
supportFragmentManager.beginTransaction().apply {
|
||||||
replace(R.id.fragment_container, JavaFragment())
|
replace(
|
||||||
|
R.id.fragment_container,
|
||||||
|
JavaFragment()
|
||||||
|
)
|
||||||
addToBackStack(null)
|
addToBackStack(null)
|
||||||
}.commit()
|
}.commit()
|
||||||
selected = 1
|
selected = 1
|
||||||
|
@ -63,7 +77,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
R.id.menu_apng_decoder_fragment -> {
|
R.id.menu_apng_decoder_fragment -> {
|
||||||
if (selected != 2) {
|
if (selected != 2) {
|
||||||
supportFragmentManager.beginTransaction().apply {
|
supportFragmentManager.beginTransaction().apply {
|
||||||
replace(R.id.fragment_container, ApngDecoderFragment.newInstance())
|
replace(
|
||||||
|
R.id.fragment_container,
|
||||||
|
ApngDecoderFragment.newInstance()
|
||||||
|
)
|
||||||
addToBackStack(null)
|
addToBackStack(null)
|
||||||
}.commit()
|
}.commit()
|
||||||
selected = 2
|
selected = 2
|
||||||
|
@ -80,21 +97,29 @@ class MainActivity : AppCompatActivity() {
|
||||||
when(intent.getStringExtra("fragment")) {
|
when(intent.getStringExtra("fragment")) {
|
||||||
"kotlin" -> {
|
"kotlin" -> {
|
||||||
supportFragmentManager.beginTransaction().apply {
|
supportFragmentManager.beginTransaction().apply {
|
||||||
add(R.id.fragment_container, KotlinFragment.newInstance(), "KotlinFragment")
|
add(
|
||||||
|
R.id.fragment_container,
|
||||||
|
KotlinFragment.newInstance(), "KotlinFragment")
|
||||||
}.commit()
|
}.commit()
|
||||||
navigationView.setCheckedItem(R.id.menu_kotlin_fragment)
|
navigationView.setCheckedItem(R.id.menu_kotlin_fragment)
|
||||||
selected = 0
|
selected = 0
|
||||||
}
|
}
|
||||||
"java" -> {
|
"java" -> {
|
||||||
supportFragmentManager.beginTransaction().apply {
|
supportFragmentManager.beginTransaction().apply {
|
||||||
add(R.id.fragment_container, JavaFragment())
|
add(
|
||||||
|
R.id.fragment_container,
|
||||||
|
JavaFragment()
|
||||||
|
)
|
||||||
}.commit()
|
}.commit()
|
||||||
navigationView.setCheckedItem(R.id.menu_java_fragment)
|
navigationView.setCheckedItem(R.id.menu_java_fragment)
|
||||||
selected = 1
|
selected = 1
|
||||||
}
|
}
|
||||||
"apng_decoder" -> {
|
"apng_decoder" -> {
|
||||||
supportFragmentManager.beginTransaction().apply {
|
supportFragmentManager.beginTransaction().apply {
|
||||||
add(R.id.fragment_container, ApngDecoderFragment.newInstance())
|
add(
|
||||||
|
R.id.fragment_container,
|
||||||
|
ApngDecoderFragment.newInstance()
|
||||||
|
)
|
||||||
}.commit()
|
}.commit()
|
||||||
navigationView.setCheckedItem(R.id.menu_apng_decoder_fragment)
|
navigationView.setCheckedItem(R.id.menu_apng_decoder_fragment)
|
||||||
selected = 2
|
selected = 2
|
||||||
|
@ -102,7 +127,9 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
supportFragmentManager.beginTransaction().apply {
|
supportFragmentManager.beginTransaction().apply {
|
||||||
add(R.id.fragment_container, KotlinFragment.newInstance(), "KotlinFragment")
|
add(
|
||||||
|
R.id.fragment_container,
|
||||||
|
KotlinFragment.newInstance(), "KotlinFragment")
|
||||||
}.commit()
|
}.commit()
|
||||||
navigationView.setCheckedItem(R.id.menu_kotlin_fragment)
|
navigationView.setCheckedItem(R.id.menu_kotlin_fragment)
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package oupson.apngcreator
|
package oupson.apngcreator.activities
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
@ -11,8 +11,9 @@ import kotlinx.android.synthetic.main.activity_viewer.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import oupson.apng.ApngDecoder
|
||||||
import oupson.apng.CustomAnimationDrawable
|
import oupson.apng.CustomAnimationDrawable
|
||||||
import oupson.apng.ExperimentalApngDecoder
|
import oupson.apngcreator.R
|
||||||
|
|
||||||
class ViewerActivity : AppCompatActivity() {
|
class ViewerActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -43,7 +44,7 @@ class ViewerActivity : AppCompatActivity() {
|
||||||
val uri = intent.data ?: return
|
val uri = intent.data ?: return
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
//val animator = imageView.loadApng(uri, null)
|
//val animator = imageView.loadApng(uri, null)
|
||||||
val drawable = ExperimentalApngDecoder.decodeApng(this@ViewerActivity, uri)
|
val drawable = ApngDecoder.decodeApng(this@ViewerActivity, uri)
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
viewerImageView.setImageDrawable(drawable)
|
viewerImageView.setImageDrawable(drawable)
|
||||||
if (drawable is CustomAnimationDrawable)
|
if (drawable is CustomAnimationDrawable)
|
|
@ -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<T>(itemFactory: () -> List<T>,
|
|
||||||
val viewFactory: Context.(index: Int, items: List<T>, view: View?) -> View
|
|
||||||
): BaseAdapter() {
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
val items: List<T> 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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<Uri>) : RecyclerView.Adapter<ImageAdapter.ImageHolder>() {
|
||||||
|
val delay : ArrayList<String> = arrayListOf()
|
||||||
|
val listeners : ArrayList<Listener> = 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<ImageView?>(R.id.listImageView)
|
||||||
|
val textDelay = view.findViewById<TextInputEditText?>(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()
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package oupson.apngcreator
|
package oupson.apngcreator.fragments
|
||||||
|
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
@ -9,7 +9,9 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.fragment.app.Fragment
|
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
|
import java.net.URL
|
||||||
|
|
||||||
class ApngDecoderFragment : Fragment() {
|
class ApngDecoderFragment : Fragment() {
|
||||||
|
@ -30,11 +32,11 @@ class ApngDecoderFragment : Fragment() {
|
||||||
val imageView : ImageView = view.findViewById(R.id.apngDecoderImageView) ?: return view
|
val imageView : ImageView = view.findViewById(R.id.apngDecoderImageView) ?: return view
|
||||||
|
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
ExperimentalApngDecoder.decodeApngAsyncInto(
|
ApngDecoder.decodeApngAsyncInto(
|
||||||
this.context!!,
|
this.context!!,
|
||||||
URL("http://littlesvr.ca/apng/images/GenevaDrive.png"),
|
URL("https://metagif.files.wordpress.com/2015/01/bugbuckbunny.png"),
|
||||||
imageView,
|
imageView,
|
||||||
callback = object : ExperimentalApngDecoder.Callback {
|
callback = object : ApngDecoder.Callback {
|
||||||
override fun onSuccess(drawable: Drawable) {
|
override fun onSuccess(drawable: Drawable) {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
Log.i(TAG, "onSuccess()")
|
Log.i(TAG, "onSuccess()")
|
|
@ -1,4 +1,4 @@
|
||||||
package oupson.apngcreator;
|
package oupson.apngcreator.fragments;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -14,7 +14,8 @@ import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import oupson.apng.ExperimentalApngDecoder;
|
import oupson.apng.ApngDecoder;
|
||||||
|
import oupson.apngcreator.R;
|
||||||
|
|
||||||
|
|
||||||
public class JavaFragment extends Fragment {
|
public class JavaFragment extends Fragment {
|
||||||
|
@ -45,7 +46,7 @@ public class JavaFragment extends Fragment {
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
ExperimentalApngDecoder.decodeApngAsyncInto(context, imageUrl, imageView, 1f, new ExperimentalApngDecoder.Callback() {
|
ApngDecoder.decodeApngAsyncInto(context, imageUrl, imageView, 1f, new ApngDecoder.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(@NotNull Drawable drawable) {
|
public void onSuccess(@NotNull Drawable drawable) {
|
||||||
Log.i(TAG, "Success");
|
Log.i(TAG, "Success");
|
|
@ -1,4 +1,4 @@
|
||||||
package oupson.apngcreator
|
package oupson.apngcreator.fragments
|
||||||
|
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -13,6 +13,8 @@ import androidx.fragment.app.Fragment
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import oupson.apng.ApngAnimator
|
import oupson.apng.ApngAnimator
|
||||||
import oupson.apng.loadApng
|
import oupson.apng.loadApng
|
||||||
|
import oupson.apngcreator.BuildConfig
|
||||||
|
import oupson.apngcreator.R
|
||||||
|
|
||||||
|
|
||||||
class KotlinFragment : Fragment() {
|
class KotlinFragment : Fragment() {
|
||||||
|
@ -102,9 +104,9 @@ class KotlinFragment : Fragment() {
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
Log.i(TAG, "onPause()")
|
Log.i(TAG, "onPause()")
|
||||||
|
|
||||||
// animator = null
|
animator = null
|
||||||
normalImageView?.setImageDrawable(null)
|
normalImageView?.setImageDrawable(null)
|
||||||
// apngImageView?.setImageDrawable(null)
|
apngImageView?.setImageDrawable(null)
|
||||||
|
|
||||||
playButton?.setOnClickListener(null)
|
playButton?.setOnClickListener(null)
|
||||||
pauseButton?.setOnClickListener(null)
|
pauseButton?.setOnClickListener(null)
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24.0"
|
android:viewportWidth="24.0"
|
||||||
android:viewportHeight="24.0">
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#000"
|
android:fillColor="#fff"
|
||||||
android:pathData="M8,5v14l11,-7z"/>
|
android:pathData="M8,5v14l11,-7z"/>
|
||||||
</vector>
|
</vector>
|
|
@ -1,6 +1,31 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical" android:layout_width="match_parent"
|
android:orientation="vertical" android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
</LinearLayout>
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/imageRecyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginBottom="?actionBarSize" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fabAddImage"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:tint="#fff"
|
||||||
|
app:backgroundTint="@color/secondary"
|
||||||
|
app:layout_anchor="@id/creatorBottomAppBar"
|
||||||
|
app:layout_anchorGravity="bottom|right|end"
|
||||||
|
app:srcCompat="@drawable/ic_add_black_24dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.bottomappbar.BottomAppBar
|
||||||
|
android:id="@+id/creatorBottomAppBar"
|
||||||
|
style="@style/Widget.MaterialComponents.BottomAppBar.Colored"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom" />
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -7,8 +7,7 @@
|
||||||
android:id="@+id/drawer_layout">
|
android:id="@+id/drawer_layout">
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:background="@color/background">
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/fragment_container"
|
android:id="@+id/fragment_container"
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:background="#323232">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/viewerImageView"
|
android:id="@+id/viewerImageView"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ApngDecoderFragment">
|
tools:context=".fragments.ApngDecoderFragment">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/apngDecoderImageView"
|
android:id="@+id/apngDecoderImageView"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
tools:context=".JavaFragment">
|
tools:context=".fragments.JavaFragment">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/javaImageView"
|
android:id="@+id/javaImageView"
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:background="@color/background">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -20,7 +19,8 @@
|
||||||
app:layout_constraintBottom_toTopOf="@id/NormalImageView"
|
app:layout_constraintBottom_toTopOf="@id/NormalImageView"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:contentDescription="@string/description_viewer_imageView"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/NormalImageView"
|
android:id="@+id/NormalImageView"
|
||||||
|
@ -33,7 +33,8 @@
|
||||||
app:layout_constraintBottom_toTopOf="@+id/SpeedSeekBar"
|
app:layout_constraintBottom_toTopOf="@+id/SpeedSeekBar"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/ApngImageView" />
|
app:layout_constraintTop_toBottomOf="@id/ApngImageView"
|
||||||
|
android:contentDescription="@string/description_viewer_imageView" />
|
||||||
|
|
||||||
<SeekBar
|
<SeekBar
|
||||||
android:id="@+id/SpeedSeekBar"
|
android:id="@+id/SpeedSeekBar"
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<oupson.apngcreator.views.SquareImageView
|
||||||
|
android:id="@+id/listImageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/textInputLayout"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/textInputLayout"
|
||||||
|
tools:srcCompat="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/textInputLayout"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:hint="@string/delay"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/listImageView"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/textDelay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:inputType="number"
|
||||||
|
android:text="1000"
|
||||||
|
android:textColorHint="@color/colorPrimary"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_create_apng"
|
||||||
|
android:icon="@drawable/ic_play_arrow_white_24dp"
|
||||||
|
android:title="@string/create"
|
||||||
|
app:showAsAction="ifRoom"
|
||||||
|
app:iconTint="@color/control"/>
|
||||||
|
</menu>
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<bool name="is_theme_light">false</bool>
|
<bool name="is_theme_light">false</bool>
|
||||||
|
<bool name="nav_bar_light">true</bool>
|
||||||
</resources>
|
</resources>
|
|
@ -6,5 +6,5 @@
|
||||||
|
|
||||||
<color name="background">#000</color>
|
<color name="background">#000</color>
|
||||||
|
|
||||||
<color name="control">#fff</color>
|
<color name="control">#000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<bool name="is_theme_light">true</bool>
|
<bool name="is_theme_light">true</bool>
|
||||||
|
<bool name="nav_bar_light">false</bool>
|
||||||
</resources>
|
</resources>
|
|
@ -1,10 +1,6 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">APNGCreator</string>
|
<string name="app_name">APNGCreator</string>
|
||||||
|
|
||||||
<string name="create_apng">Create APNG</string>
|
|
||||||
<string name="java_activity">Java Activity</string>
|
|
||||||
<string name="apng_imageView">An ImageView with an APNG</string>
|
|
||||||
|
|
||||||
<string name="description_viewer_imageView">Loaded Image</string>
|
<string name="description_viewer_imageView">Loaded Image</string>
|
||||||
|
|
||||||
<string name="title_playButton">Play</string>
|
<string name="title_playButton">Play</string>
|
||||||
|
@ -18,7 +14,5 @@
|
||||||
|
|
||||||
<string name="open">open</string>
|
<string name="open">open</string>
|
||||||
<string name="close">close</string>
|
<string name="close">close</string>
|
||||||
|
<string name="delay">Delay (ms)</string>
|
||||||
<!-- TODO: Remove or change this placeholder text -->
|
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -9,8 +9,11 @@
|
||||||
<item name="android:textColorPrimary">@color/text</item>
|
<item name="android:textColorPrimary">@color/text</item>
|
||||||
<item name="android:textColorSecondary">@color/text</item>
|
<item name="android:textColorSecondary">@color/text</item>
|
||||||
|
|
||||||
|
<item name="android:windowBackground">@color/background</item>
|
||||||
|
|
||||||
<item name="android:windowLightStatusBar" tools:targetApi="m">@bool/is_theme_light</item>
|
<item name="android:windowLightStatusBar" tools:targetApi="m">@bool/is_theme_light</item>
|
||||||
<item name="android:navigationBarColor">@color/colorPrimary</item>
|
<item name="android:navigationBarColor">@color/colorPrimary</item>
|
||||||
|
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">@bool/nav_bar_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppShapeAppearance.MediumComponent" parent="ShapeAppearance.MaterialComponents.MediumComponent">
|
<style name="AppShapeAppearance.MediumComponent" parent="ShapeAppearance.MaterialComponents.MediumComponent">
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<!--<external-path name="external_files" path="."/>-->
|
||||||
|
<files-path path="images/" name="images" />
|
||||||
|
</paths>
|
Loading…
Reference in New Issue