From 983f2ac1411f7f8a6c0085ae3de29b3425fbce04 Mon Sep 17 00:00:00 2001 From: mikaelzero <1604165677@qq.com> Date: Fri, 30 Jul 2021 14:27:32 +0800 Subject: [PATCH] upgrade to kts --- FrescoImageLoader/build.gradle | 42 --- FrescoImageLoader/build.gradle.kts | 23 ++ .../src/main/AndroidManifest.xml | 1 - .../loader/fresco/FrescoImageLoader.java | 179 ----------- .../mojito/loader/fresco/FrescoImageLoader.kt | 141 +++++++++ .../mojito/loader/fresco/IOUtils.java | 257 ---------------- .../mojito/loader/fresco/IOUtils.kt | 263 ++++++++++++++++ .../fresco/ImageDownloadSubscriber.java | 84 ----- .../loader/fresco/ImageDownloadSubscriber.kt | 76 +++++ GlideImageLoader/build.gradle | 42 --- GlideImageLoader/build.gradle.kts | 24 ++ GlideImageLoader/src/main/AndroidManifest.xml | 1 - .../mojito/loader/glide/GlideImageLoader.kt | 3 +- README.md | 79 ++--- README_en.md | 76 ++--- SketchImageViewLoader/build.gradle | 43 --- SketchImageViewLoader/build.gradle.kts | 25 ++ app/build.gradle | 57 ---- app/build.gradle.kts | 55 ++++ .../mikaelzero/app/ActivityCoverActivity.kt | 45 ++- .../mikaelzero/app/DifferentScenesActivity.kt | 24 +- .../java/net/mikaelzero/app/MainActivity.kt | 31 +- .../net/mikaelzero/app/PreviewActivity.kt | 113 +++---- .../java/net/mikaelzero/app/TargetActivity.kt | 45 ++- .../app/local/LocalImageActivity.kt | 23 +- .../mikaelzero/app/stagger/StaggerActivity.kt | 23 +- .../net/mikaelzero/app/video/VideoActivity.kt | 42 +-- build.gradle | 36 --- build.gradle.kts | 26 ++ buildSrc/build.gradle.kts | 15 + buildSrc/plugins.gradle.kts | 5 + buildSrc/src/main/kotlin/Extensions.kt | 101 ++++++ buildSrc/src/main/kotlin/Library.kt | 68 +++++ buildSrc/src/main/kotlin/Projects.kt | 55 ++++ coilimageloader/build.gradle | 43 --- coilimageloader/build.gradle.kts | 25 ++ .../coilimageloader/CoilImageLoader.kt | 19 +- .../coilimageloader/ImageDownloadTarget.kt | 18 +- gradle.properties | 43 +-- mojito/build.gradle | 48 --- mojito/build.gradle.kts | 28 ++ .../main/java/net/mikaelzero/mojito/Mojito.kt | 30 +- .../net/mikaelzero/mojito/MojitoBuilder.kt | 289 ++++++++++++++++++ .../net/mikaelzero/mojito/MojitoWrapper.kt | 243 --------------- .../mikaelzero/mojito/bean/ActivityConfig.kt | 2 +- .../mikaelzero/mojito/bean/FragmentConfig.kt | 2 +- .../mikaelzero/mojito/ext/MojitoViewExt.kt | 34 +++ .../mojito/impl/CircleIndexIndicator.java | 93 ------ .../mojito/impl/CircleIndicator.java | 274 ----------------- .../mikaelzero/mojito/impl/NumIndicator.java | 10 +- .../mojito/interfaces/IIndicator.java | 3 +- .../mojito/tools/NoScrollViewPager.java | 60 ---- .../mojito/ui/ImageMojitoActivity.kt | 73 +++-- .../mojito/ui/ImageMojitoFragment.kt | 54 ++-- mojito/src/main/res/layout/activity_image.xml | 2 +- settings.gradle | 5 - settings.gradle.kts | 6 + 57 files changed, 1609 insertions(+), 1918 deletions(-) delete mode 100644 FrescoImageLoader/build.gradle create mode 100644 FrescoImageLoader/build.gradle.kts delete mode 100644 FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.java create mode 100644 FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.kt delete mode 100644 FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.java create mode 100644 FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.kt delete mode 100644 FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.java create mode 100644 FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.kt delete mode 100644 GlideImageLoader/build.gradle create mode 100644 GlideImageLoader/build.gradle.kts delete mode 100644 SketchImageViewLoader/build.gradle create mode 100644 SketchImageViewLoader/build.gradle.kts delete mode 100644 app/build.gradle create mode 100644 app/build.gradle.kts delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/plugins.gradle.kts create mode 100644 buildSrc/src/main/kotlin/Extensions.kt create mode 100644 buildSrc/src/main/kotlin/Library.kt create mode 100644 buildSrc/src/main/kotlin/Projects.kt delete mode 100644 coilimageloader/build.gradle create mode 100644 coilimageloader/build.gradle.kts delete mode 100644 mojito/build.gradle create mode 100644 mojito/build.gradle.kts create mode 100644 mojito/src/main/java/net/mikaelzero/mojito/MojitoBuilder.kt delete mode 100644 mojito/src/main/java/net/mikaelzero/mojito/MojitoWrapper.kt create mode 100644 mojito/src/main/java/net/mikaelzero/mojito/ext/MojitoViewExt.kt delete mode 100644 mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndexIndicator.java delete mode 100644 mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndicator.java delete mode 100644 mojito/src/main/java/net/mikaelzero/mojito/tools/NoScrollViewPager.java delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/FrescoImageLoader/build.gradle b/FrescoImageLoader/build.gradle deleted file mode 100644 index a666b84..0000000 --- a/FrescoImageLoader/build.gradle +++ /dev/null @@ -1,42 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'com.github.dcendents.android-maven' -group = 'com.github.mikaelzero' -android { - def globalConfiguration = rootProject.extensions.getByName("ext") - compileSdkVersion globalConfiguration.androidCompileSdkVersion - - defaultConfig { - minSdkVersion globalConfiguration.androidMinSdkVersion - targetSdkVersion globalConfiguration.androidTargetSdkVersion - versionCode 1 - versionName "1.0" - consumerProguardFiles "consumer-rules.pro" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - buildToolsVersion '30.0.3' -} - -dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation "com.facebook.fresco:fresco:2.1.0" - implementation "androidx.annotation:annotation:1.2.0" - implementation project(':mojito') -} diff --git a/FrescoImageLoader/build.gradle.kts b/FrescoImageLoader/build.gradle.kts new file mode 100644 index 0000000..6ccd4b0 --- /dev/null +++ b/FrescoImageLoader/build.gradle.kts @@ -0,0 +1,23 @@ +import mojito.setupLibraryModule + +plugins { + id("com.android.library") + id("kotlin-android") + id("com.github.dcendents.android-maven") +} + +group = "com.github.mikaelzero" +setupLibraryModule { + defaultConfig { + minSdk = 16 + } +} +dependencies { + implementation(mojito.Library.KOTLINX_STDLIB) + implementation(mojito.Library.ANDROIDX_APPCOMPAT) + implementation(mojito.Library.ANDROIDX_CORE) + implementation(mojito.Library.OKHTTP) + implementation("com.facebook.fresco:fresco:2.1.0") + implementation("androidx.annotation:annotation:1.2.0") + implementation(project(":mojito")) +} diff --git a/FrescoImageLoader/src/main/AndroidManifest.xml b/FrescoImageLoader/src/main/AndroidManifest.xml index f5fb063..abf2557 100644 --- a/FrescoImageLoader/src/main/AndroidManifest.xml +++ b/FrescoImageLoader/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - / \ No newline at end of file diff --git a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.java b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.java deleted file mode 100644 index eef9f3e..0000000 --- a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.java +++ /dev/null @@ -1,179 +0,0 @@ -package net.mikaelzero.mojito.loader.fresco; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.net.Uri; - -import com.facebook.binaryresource.FileBinaryResource; -import com.facebook.cache.common.CacheKey; -import com.facebook.cache.disk.FileCache; -import com.facebook.common.memory.PooledByteBuffer; -import com.facebook.common.references.CloseableReference; -import com.facebook.datasource.DataSource; -import com.facebook.drawee.backends.pipeline.DraweeConfig; -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory; -import com.facebook.imagepipeline.core.DefaultExecutorSupplier; -import com.facebook.imagepipeline.core.ImagePipeline; -import com.facebook.imagepipeline.core.ImagePipelineConfig; -import com.facebook.imagepipeline.core.ImagePipelineFactory; -import com.facebook.imagepipeline.request.ImageRequest; - -import net.mikaelzero.mojito.loader.ImageInfoExtractor; -import net.mikaelzero.mojito.loader.ImageLoader; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public final class FrescoImageLoader implements ImageLoader { - - private final Context mAppContext; - private final DefaultExecutorSupplier mExecutorSupplier; - - private final Map mFlyingRequestSources = new HashMap<>(3); - // we create a temp image file on cache miss to make it work, - // so we need delete this temp image file when we are detached from window - // (BigImageView will call cancel). - private final Map mCacheMissTempFiles = new HashMap<>(3); - - private FrescoImageLoader(Context appContext) { - mAppContext = appContext; - mExecutorSupplier = new DefaultExecutorSupplier(Runtime.getRuntime().availableProcessors()); - } - - public static FrescoImageLoader with(Context appContext) { - return with(appContext, null, null); - } - - public static FrescoImageLoader with(Context appContext, - ImagePipelineConfig imagePipelineConfig) { - return with(appContext, imagePipelineConfig, null); - } - - public static FrescoImageLoader with(Context appContext, - ImagePipelineConfig imagePipelineConfig, DraweeConfig draweeConfig) { - Fresco.initialize(appContext, imagePipelineConfig, draweeConfig); - return new FrescoImageLoader(appContext); - } - - @SuppressLint("WrongThread") - @Override - public void loadImage(final int requestId, Uri uri, boolean onlyRetrieveFromCache, final Callback callback) { - ImageRequest request = ImageRequest.fromUri(uri); - final File localCache = getCacheFile(request); - if (onlyRetrieveFromCache && !localCache.exists()) { - callback.onFail(new Exception("")); - return; - } - if (localCache.exists()) { - mExecutorSupplier.forLocalStorageRead().execute(new Runnable() { - @Override - public void run() { - callback.onSuccess(localCache); - } - }); - } else { - callback.onStart(); // ensure `onStart` is called before `onProgress` and `onFinish` - callback.onProgress(0); // show 0 progress immediately - - ImagePipeline pipeline = Fresco.getImagePipeline(); - DataSource> source = pipeline.fetchEncodedImage(request, true); - source.subscribe(new ImageDownloadSubscriber(mAppContext) { - @Override - protected void onProgress(int progress) { - callback.onProgress(progress); - } - - @Override - protected void onSuccess(final File image) { - rememberTempFile(requestId, image); - callback.onFinish(); - callback.onSuccess(image); - } - - @Override - protected void onFail(final Throwable t) { - t.printStackTrace(); - callback.onFail((Exception) t); - } - }, mExecutorSupplier.forBackgroundTasks()); - - cancel(requestId); - rememberSource(requestId, source); - } - } - - @Override - public void prefetch(Uri uri) { - ImagePipeline pipeline = Fresco.getImagePipeline(); - pipeline.prefetchToDiskCache(ImageRequest.fromUri(uri), - false); // we don't need context, but avoid null - } - - @Override - public synchronized void cancel(int requestId) { - closeSource(mFlyingRequestSources.remove(requestId)); - deleteTempFile(mCacheMissTempFiles.remove(requestId)); - } - - @Override - public synchronized void cancelAll() { - List sources = new ArrayList<>(mFlyingRequestSources.values()); - mFlyingRequestSources.clear(); - for (DataSource source : sources) { - closeSource(source); - } - - List tempFiles = new ArrayList<>(mCacheMissTempFiles.values()); - mCacheMissTempFiles.clear(); - for (File tempFile : tempFiles) { - deleteTempFile(tempFile); - } - } - - @Override - public void cleanCache() { - ImagePipeline imagePipeline = Fresco.getImagePipeline(); - imagePipeline.clearMemoryCaches(); - imagePipeline.clearDiskCaches(); - imagePipeline.clearCaches(); - } - - private synchronized void rememberSource(int requestId, DataSource source) { - mFlyingRequestSources.put(requestId, source); - } - - private void closeSource(DataSource source) { - if (source != null) { - source.close(); - } - } - - private synchronized void rememberTempFile(int requestId, File tempFile) { - mCacheMissTempFiles.put(requestId, tempFile); - } - - private void deleteTempFile(File tempFile) { - if (tempFile != null) { - tempFile.delete(); - } - } - - private File getCacheFile(final ImageRequest request) { - FileCache mainFileCache = ImagePipelineFactory - .getInstance() - .getMainFileCache(); - final CacheKey cacheKey = DefaultCacheKeyFactory - .getInstance() - .getEncodedCacheKey(request, false); // we don't need context, but avoid null - File cacheFile = request.getSourceFile(); - // http://crashes.to/s/ee10638fb31 - if (mainFileCache.hasKey(cacheKey) && mainFileCache.getResource(cacheKey) != null) { - cacheFile = ((FileBinaryResource) mainFileCache.getResource(cacheKey)).getFile(); - } - return cacheFile; - } -} diff --git a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.kt b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.kt new file mode 100644 index 0000000..4ff5e47 --- /dev/null +++ b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/FrescoImageLoader.kt @@ -0,0 +1,141 @@ +package net.mikaelzero.mojito.loader.fresco + +import android.annotation.SuppressLint +import android.content.Context +import android.net.Uri +import com.facebook.binaryresource.FileBinaryResource +import com.facebook.datasource.DataSource +import com.facebook.drawee.backends.pipeline.DraweeConfig +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory +import com.facebook.imagepipeline.core.DefaultExecutorSupplier +import com.facebook.imagepipeline.core.ImagePipelineConfig +import com.facebook.imagepipeline.core.ImagePipelineFactory +import com.facebook.imagepipeline.request.ImageRequest +import net.mikaelzero.mojito.loader.ImageLoader +import java.io.File + +class FrescoImageLoader private constructor(private val mAppContext: Context) : ImageLoader { + private val mExecutorSupplier: DefaultExecutorSupplier = DefaultExecutorSupplier(Runtime.getRuntime().availableProcessors()) + private val mFlyingRequestSources: MutableMap> = HashMap(3) + + // we create a temp image file on cache miss to make it work, + // so we need delete this temp image file when we are detached from window + // (BigImageView will call cancel). + private val mCacheMissTempFiles: MutableMap = HashMap(3) + @SuppressLint("WrongThread") + override fun loadImage(requestId: Int, uri: Uri, onlyRetrieveFromCache: Boolean, callback: ImageLoader.Callback) { + val request = ImageRequest.fromUri(uri) + val localCache = getCacheFile(request) + if (onlyRetrieveFromCache && !localCache.exists()) { + callback.onFail(Exception("")) + return + } + if (localCache.exists()) { + mExecutorSupplier.forLocalStorageRead().execute { callback.onSuccess(localCache) } + } else { + callback.onStart() // ensure `onStart` is called before `onProgress` and `onFinish` + callback.onProgress(0) // show 0 progress immediately + val pipeline = Fresco.getImagePipeline() + val source = pipeline.fetchEncodedImage(request, true) + source.subscribe(object : ImageDownloadSubscriber(mAppContext) { + override fun onProgress(progress: Int) { + callback.onProgress(progress) + } + + override fun onSuccess(image: File?) { + rememberTempFile(requestId, image) + callback.onFinish() + callback.onSuccess(image) + } + + override fun onFail(t: Throwable?) { + t!!.printStackTrace() + callback.onFail(t as Exception?) + } + }, mExecutorSupplier.forBackgroundTasks()) + cancel(requestId) + rememberSource(requestId, source) + } + } + + override fun prefetch(uri: Uri) { + val pipeline = Fresco.getImagePipeline() + pipeline.prefetchToDiskCache( + ImageRequest.fromUri(uri), + false + ) // we don't need context, but avoid null + } + + @Synchronized + override fun cancel(requestId: Int) { + closeSource(mFlyingRequestSources.remove(requestId)) + deleteTempFile(mCacheMissTempFiles.remove(requestId)) + } + + @Synchronized + override fun cancelAll() { + val sources: List> = ArrayList(mFlyingRequestSources.values) + mFlyingRequestSources.clear() + for (source in sources) { + closeSource(source) + } + val tempFiles: List = ArrayList(mCacheMissTempFiles.values) + mCacheMissTempFiles.clear() + for (tempFile in tempFiles) { + deleteTempFile(tempFile) + } + } + + override fun cleanCache() { + val imagePipeline = Fresco.getImagePipeline() + imagePipeline.clearMemoryCaches() + imagePipeline.clearDiskCaches() + imagePipeline.clearCaches() + } + + @Synchronized + private fun rememberSource(requestId: Int, source: DataSource<*>) { + mFlyingRequestSources[requestId] = source + } + + private fun closeSource(source: DataSource<*>?) { + source?.close() + } + + @Synchronized + private fun rememberTempFile(requestId: Int, tempFile: File?) { + mCacheMissTempFiles[requestId] = tempFile + } + + private fun deleteTempFile(tempFile: File?) { + tempFile?.delete() + } + + private fun getCacheFile(request: ImageRequest?): File { + val mainFileCache = ImagePipelineFactory + .getInstance() + .mainFileCache + val cacheKey = DefaultCacheKeyFactory + .getInstance() + .getEncodedCacheKey(request, false) // we don't need context, but avoid null + var cacheFile = request!!.sourceFile + // http://crashes.to/s/ee10638fb31 + if (mainFileCache.hasKey(cacheKey) && mainFileCache.getResource(cacheKey) != null) { + cacheFile = (mainFileCache.getResource(cacheKey) as FileBinaryResource).file + } + return cacheFile + } + + companion object { + @JvmOverloads + fun with( + appContext: Context, + imagePipelineConfig: ImagePipelineConfig? = null, draweeConfig: DraweeConfig? = null + ): FrescoImageLoader { + Fresco.initialize(appContext, imagePipelineConfig, draweeConfig) + return FrescoImageLoader(appContext) + } + } + +} \ No newline at end of file diff --git a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.java b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.java deleted file mode 100644 index c5f7669..0000000 --- a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.java +++ /dev/null @@ -1,257 +0,0 @@ -package net.mikaelzero.mojito.loader.fresco; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; - -public class IOUtils { - - /** - * The default buffer size ({@value}) to use for - * {@link #copyLarge(InputStream, OutputStream)} - * and - * {@link #copyLarge(Reader, Writer)} - */ - private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - - /** - * The default buffer size to use for the skip() methods. - */ - private static final int SKIP_BUFFER_SIZE = 2048; - - /** - * Represents the end-of-file (or stream). - * - * @since 2.5 (made public) - */ - public static final int EOF = -1; - -// copy from InputStream - //----------------------------------------------------------------------- - - /** - * Copies bytes from an InputStream to an - * OutputStream. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - *

- * Large streams (over 2GB) will return a bytes copied value of - * -1 after the copy has completed since the correct - * number of bytes cannot be returned as an int. For large streams - * use the copyLarge(InputStream, OutputStream) method. - * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static int copy(final InputStream input, final OutputStream output) throws IOException { - final long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } - - /** - * Copies bytes from an InputStream to an OutputStream using an internal buffer of the - * given size. - *

- * This method buffers the input internally, so there is no need to use a BufferedInputStream. - *

- * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @param bufferSize the bufferSize used to copy from the input to the output - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.5 - */ - public static long copy(final InputStream input, final OutputStream output, final int bufferSize) - throws IOException { - return copyLarge(input, output, new byte[bufferSize]); - } - - /** - * Copies bytes from a large (over 2GB) InputStream to an - * OutputStream. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.3 - */ - public static long copyLarge(final InputStream input, final OutputStream output) - throws IOException { - return copy(input, output, DEFAULT_BUFFER_SIZE); - } - - /** - * Copies bytes from a large (over 2GB) InputStream to an - * OutputStream. - *

- * This method uses the provided buffer, so there is no need to use a - * BufferedInputStream. - *

- * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @param buffer the buffer to use for the copy - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - public static long copyLarge(final InputStream input, final OutputStream output, final byte[] buffer) - throws IOException { - long count = 0; - int n; - while (EOF != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - // copy from Reader - //----------------------------------------------------------------------- - - /** - * Copies chars from a Reader to a Writer. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - *

- * Large streams (over 2GB) will return a chars copied value of - * -1 after the copy has completed since the correct - * number of chars cannot be returned as an int. For large streams - * use the copyLarge(Reader, Writer) method. - * - * @param input the Reader to read from - * @param output the Writer to write to - * @return the number of characters copied, or -1 if > Integer.MAX_VALUE - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static int copy(final Reader input, final Writer output) throws IOException { - final long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } - - /** - * Copies chars from a large (over 2GB) Reader to a Writer. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedReader. - *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - * - * @param input the Reader to read from - * @param output the Writer to write to - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.3 - */ - public static long copyLarge(final Reader input, final Writer output) throws IOException { - return copyLarge(input, output, new char[DEFAULT_BUFFER_SIZE]); - } - - /** - * Copies chars from a large (over 2GB) Reader to a Writer. - *

- * This method uses the provided buffer, so there is no need to use a - * BufferedReader. - *

- * - * @param input the Reader to read from - * @param output the Writer to write to - * @param buffer the buffer to be used for the copy - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - public static long copyLarge(final Reader input, final Writer output, final char[] buffer) throws IOException { - long count = 0; - int n; - while (EOF != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Closes an InputStream unconditionally. - *

- * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param inputStream InputStream - */ - public static void closeQuietly(InputStream inputStream) { - if (inputStream != null) { - try { - inputStream.close(); - } catch (Exception ignored) { - // ignored - } - } - } - - /** - * Closes an OutputStream unconditionally. - *

- * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param outputStream OutputStream - */ - - public static void closeQuietly(OutputStream outputStream) { - if (outputStream != null) { - try { - outputStream.close(); - } catch (Exception ignored) { - // ignored - } - } - } - - /** - * Closes an BufferedReader unconditionally. - *

- * Equivalent to {@link BufferedReader#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - * - * @param bufferedReader BufferedReader - */ - public static void closeQuietly(BufferedReader bufferedReader) { - if (bufferedReader != null) { - try { - bufferedReader.close(); - } catch (Exception ignored) { - // ignored - } - } - } -} diff --git a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.kt b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.kt new file mode 100644 index 0000000..9c7ea33 --- /dev/null +++ b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/IOUtils.kt @@ -0,0 +1,263 @@ +package net.mikaelzero.mojito.loader.fresco + +import java.io.* +import java.lang.Exception +import kotlin.Throws +import kotlin.jvm.JvmOverloads + +object IOUtils { + /** + * The default buffer size ({@value}) to use for + * [.copyLarge] + * and + * [.copyLarge] + */ + private const val DEFAULT_BUFFER_SIZE = 1024 * 4 + + /** + * The default buffer size to use for the skip() methods. + */ + private const val SKIP_BUFFER_SIZE = 2048 + + /** + * Represents the end-of-file (or stream). + * + * @since 2.5 (made public) + */ + const val EOF = -1 + // copy from InputStream + //----------------------------------------------------------------------- + /** + * Copies bytes from an `InputStream` to an + * `OutputStream`. + * + * + * This method buffers the input internally, so there is no need to use a + * `BufferedInputStream`. + * + * + * Large streams (over 2GB) will return a bytes copied value of + * `-1` after the copy has completed since the correct + * number of bytes cannot be returned as an int. For large streams + * use the `copyLarge(InputStream, OutputStream)` method. + * + * @param input the `InputStream` to read from + * @param output the `OutputStream` to write to + * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + @Throws(IOException::class) + fun copy(input: InputStream, output: OutputStream): Int { + val count = copyLarge(input, output) + return if (count > Int.MAX_VALUE) { + -1 + } else count.toInt() + } + + /** + * Copies bytes from an `InputStream` to an `OutputStream` using an internal buffer of the + * given size. + * + * + * This method buffers the input internally, so there is no need to use a `BufferedInputStream`. + * + * + * + * @param input the `InputStream` to read from + * @param output the `OutputStream` to write to + * @param bufferSize the bufferSize used to copy from the input to the output + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.5 + */ + @Throws(IOException::class) + fun copy(input: InputStream, output: OutputStream, bufferSize: Int): Long { + return copyLarge(input, output, ByteArray(bufferSize)) + } + + /** + * Copies bytes from a large (over 2GB) `InputStream` to an + * `OutputStream`. + * + * + * This method buffers the input internally, so there is no need to use a + * `BufferedInputStream`. + * + * + * The buffer size is given by [.DEFAULT_BUFFER_SIZE]. + * + * @param input the `InputStream` to read from + * @param output the `OutputStream` to write to + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.3 + */ + @Throws(IOException::class) + fun copyLarge(input: InputStream, output: OutputStream): Long { + return copy(input, output, DEFAULT_BUFFER_SIZE) + } + + /** + * Copies bytes from a large (over 2GB) `InputStream` to an + * `OutputStream`. + * + * + * This method uses the provided buffer, so there is no need to use a + * `BufferedInputStream`. + * + * + * + * @param input the `InputStream` to read from + * @param output the `OutputStream` to write to + * @param buffer the buffer to use for the copy + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + @Throws(IOException::class) + fun copyLarge(input: InputStream, output: OutputStream, buffer: ByteArray?): Long { + var count: Long = 0 + var n: Int + while (EOF != input.read(buffer).also { n = it }) { + output.write(buffer, 0, n) + count += n.toLong() + } + return count + } + // copy from Reader + //----------------------------------------------------------------------- + /** + * Copies chars from a `Reader` to a `Writer`. + * + * + * This method buffers the input internally, so there is no need to use a + * `BufferedReader`. + * + * + * Large streams (over 2GB) will return a chars copied value of + * `-1` after the copy has completed since the correct + * number of chars cannot be returned as an int. For large streams + * use the `copyLarge(Reader, Writer)` method. + * + * @param input the `Reader` to read from + * @param output the `Writer` to write to + * @return the number of characters copied, or -1 if > Integer.MAX_VALUE + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + @Throws(IOException::class) + fun copy(input: Reader, output: Writer): Int { + val count = copyLarge(input, output) + return if (count > Int.MAX_VALUE) { + -1 + } else count.toInt() + } + /** + * Copies chars from a large (over 2GB) `Reader` to a `Writer`. + * + * + * This method uses the provided buffer, so there is no need to use a + * `BufferedReader`. + * + * + * + * @param input the `Reader` to read from + * @param output the `Writer` to write to + * @param buffer the buffer to be used for the copy + * @return the number of characters copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + /** + * Copies chars from a large (over 2GB) `Reader` to a `Writer`. + * + * + * This method buffers the input internally, so there is no need to use a + * `BufferedReader`. + * + * + * The buffer size is given by [.DEFAULT_BUFFER_SIZE]. + * + * @param input the `Reader` to read from + * @param output the `Writer` to write to + * @return the number of characters copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.3 + */ + @JvmOverloads + @Throws(IOException::class) + fun copyLarge(input: Reader, output: Writer, buffer: CharArray? = CharArray(DEFAULT_BUFFER_SIZE)): Long { + var count: Long = 0 + var n: Int + while (EOF != input.read(buffer).also { n = it }) { + output.write(buffer, 0, n) + count += n.toLong() + } + return count + } + + /** + * Closes an `InputStream` unconditionally. + * + * + * Equivalent to [InputStream.close], except any exceptions will be ignored. + * This is typically used in finally blocks. + * + * @param inputStream `InputStream` + */ + fun closeQuietly(inputStream: InputStream?) { + if (inputStream != null) { + try { + inputStream.close() + } catch (ignored: Exception) { + // ignored + } + } + } + + /** + * Closes an `OutputStream` unconditionally. + * + * + * Equivalent to [OutputStream.close], except any exceptions will be ignored. + * This is typically used in finally blocks. + * + * @param outputStream `OutputStream` + */ + fun closeQuietly(outputStream: OutputStream?) { + if (outputStream != null) { + try { + outputStream.close() + } catch (ignored: Exception) { + // ignored + } + } + } + + /** + * Closes an `BufferedReader` unconditionally. + * + * + * Equivalent to [BufferedReader.close], except any exceptions will be ignored. + * This is typically used in finally blocks. + * + * @param bufferedReader `BufferedReader` + */ + fun closeQuietly(bufferedReader: BufferedReader?) { + if (bufferedReader != null) { + try { + bufferedReader.close() + } catch (ignored: Exception) { + // ignored + } + } + } +} \ No newline at end of file diff --git a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.java b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.java deleted file mode 100644 index 849f518..0000000 --- a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.mikaelzero.mojito.loader.fresco; - -import android.content.Context; - -import androidx.annotation.WorkerThread; - -import com.facebook.common.memory.PooledByteBuffer; -import com.facebook.common.memory.PooledByteBufferInputStream; -import com.facebook.common.references.CloseableReference; -import com.facebook.datasource.BaseDataSubscriber; -import com.facebook.datasource.DataSource; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -public abstract class ImageDownloadSubscriber extends BaseDataSubscriber> { - private static int sCounter = 0; - - private final File mTempFile; - - private volatile boolean mFinished; - - public ImageDownloadSubscriber(Context context) { - // no need for any file extension, use a counter to avoid conflict. - mTempFile = new File(context.getCacheDir(), System.currentTimeMillis() + "_" + nextCounter()); - } - - private static synchronized int nextCounter() { - sCounter++; - return sCounter; - } - - @Override - public void onProgressUpdate(DataSource> dataSource) { - if (!mFinished) { - onProgress((int) (dataSource.getProgress() * 100)); - } - } - - @Override - protected void onNewResultImpl(DataSource> dataSource) { - if (!dataSource.isFinished()) { - return; - } - - CloseableReference closeableRef = dataSource.getResult(); - // if we try to retrieve image file by cache key, it will return null - // so we need to create a temp file, little bit hack :( - PooledByteBufferInputStream inputStream = null; - FileOutputStream outputStream = null; - try { - if (closeableRef != null) { - inputStream = new PooledByteBufferInputStream(closeableRef.get()); - outputStream = new FileOutputStream(mTempFile); - IOUtils.copy(inputStream, outputStream); - - mFinished = true; - onSuccess(mTempFile); - } - } catch (IOException e) { - onFail(e); - } finally { - CloseableReference.closeSafely(closeableRef); - IOUtils.closeQuietly(inputStream); - IOUtils.closeQuietly(outputStream); - } - } - - @Override - protected void onFailureImpl(DataSource> dataSource) { - mFinished = true; - onFail(new RuntimeException("onFailureImpl")); - } - - @WorkerThread - protected abstract void onProgress(int progress); - - @WorkerThread - protected abstract void onSuccess(File image); - - @WorkerThread - protected abstract void onFail(Throwable t); -} diff --git a/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.kt b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.kt new file mode 100644 index 0000000..205634d --- /dev/null +++ b/FrescoImageLoader/src/main/java/net/mikaelzero/mojito/loader/fresco/ImageDownloadSubscriber.kt @@ -0,0 +1,76 @@ +package net.mikaelzero.mojito.loader.fresco + +import android.content.Context +import androidx.annotation.WorkerThread +import com.facebook.common.memory.PooledByteBuffer +import com.facebook.common.memory.PooledByteBufferInputStream +import com.facebook.common.references.CloseableReference +import com.facebook.datasource.BaseDataSubscriber +import com.facebook.datasource.DataSource +import net.mikaelzero.mojito.loader.fresco.IOUtils.closeQuietly +import net.mikaelzero.mojito.loader.fresco.IOUtils.copy +import java.io.File +import java.io.FileOutputStream +import java.io.IOException + +abstract class ImageDownloadSubscriber(context: Context) : BaseDataSubscriber?>() { + private val mTempFile: File = File(context.cacheDir, System.currentTimeMillis().toString() + "_" + nextCounter()) + + @Volatile + private var mFinished = false + override fun onProgressUpdate(dataSource: DataSource?>) { + if (!mFinished) { + onProgress((dataSource.progress * 100).toInt()) + } + } + + override fun onNewResultImpl(dataSource: DataSource?>) { + if (!dataSource.isFinished) { + return + } + val closeableRef = dataSource.result + // if we try to retrieve image file by cache key, it will return null + // so we need to create a temp file, little bit hack :( + var inputStream: PooledByteBufferInputStream? = null + var outputStream: FileOutputStream? = null + try { + if (closeableRef != null) { + inputStream = PooledByteBufferInputStream(closeableRef.get()) + outputStream = FileOutputStream(mTempFile) + copy(inputStream, outputStream) + mFinished = true + onSuccess(mTempFile) + } + } catch (e: IOException) { + onFail(e) + } finally { + CloseableReference.closeSafely(closeableRef) + closeQuietly(inputStream) + closeQuietly(outputStream) + } + } + + override fun onFailureImpl(dataSource: DataSource?>) { + mFinished = true + onFail(RuntimeException("onFailureImpl")) + } + + @WorkerThread + protected abstract fun onProgress(progress: Int) + + @WorkerThread + protected abstract fun onSuccess(image: File?) + + @WorkerThread + protected abstract fun onFail(t: Throwable?) + + companion object { + private var sCounter = 0 + + @Synchronized + private fun nextCounter(): Int { + sCounter++ + return sCounter + } + } +} \ No newline at end of file diff --git a/GlideImageLoader/build.gradle b/GlideImageLoader/build.gradle deleted file mode 100644 index c357356..0000000 --- a/GlideImageLoader/build.gradle +++ /dev/null @@ -1,42 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'com.github.dcendents.android-maven' -group = 'com.github.mikaelzero' -android { - def globalConfiguration = rootProject.extensions.getByName("ext") - compileSdkVersion globalConfiguration.androidCompileSdkVersion - - defaultConfig { - minSdkVersion globalConfiguration.androidMinSdkVersion - targetSdkVersion globalConfiguration.androidTargetSdkVersion - versionCode 1 - versionName "1.0" - consumerProguardFiles "consumer-rules.pro" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - buildToolsVersion '30.0.3' -} - -dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation 'com.squareup.okhttp3:okhttp:4.9.1' - api "com.github.bumptech.glide:okhttp3-integration:4.11.0" - implementation project(':mojito') -} diff --git a/GlideImageLoader/build.gradle.kts b/GlideImageLoader/build.gradle.kts new file mode 100644 index 0000000..f171f16 --- /dev/null +++ b/GlideImageLoader/build.gradle.kts @@ -0,0 +1,24 @@ +import mojito.setupLibraryModule + +plugins { + id("com.android.library") + id("kotlin-android") + id("com.github.dcendents.android-maven") +} + +group = "com.github.mikaelzero" +setupLibraryModule { + defaultConfig { + minSdk = 16 + } +} + + +dependencies { + implementation(mojito.Library.KOTLINX_STDLIB) + implementation(mojito.Library.ANDROIDX_APPCOMPAT) + implementation(mojito.Library.ANDROIDX_CORE) + implementation(mojito.Library.OKHTTP) + api("com.github.bumptech.glide:okhttp3-integration:4.11.0") + implementation(project(":mojito")) +} diff --git a/GlideImageLoader/src/main/AndroidManifest.xml b/GlideImageLoader/src/main/AndroidManifest.xml index 5f77e48..38947e4 100644 --- a/GlideImageLoader/src/main/AndroidManifest.xml +++ b/GlideImageLoader/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - / \ No newline at end of file diff --git a/GlideImageLoader/src/main/java/net/mikaelzero/mojito/loader/glide/GlideImageLoader.kt b/GlideImageLoader/src/main/java/net/mikaelzero/mojito/loader/glide/GlideImageLoader.kt index 5045612..6e1c70f 100644 --- a/GlideImageLoader/src/main/java/net/mikaelzero/mojito/loader/glide/GlideImageLoader.kt +++ b/GlideImageLoader/src/main/java/net/mikaelzero/mojito/loader/glide/GlideImageLoader.kt @@ -15,6 +15,7 @@ import net.mikaelzero.mojito.loader.ImageLoader import okhttp3.OkHttpClient import java.io.File import java.util.* +import kotlin.concurrent.thread open class GlideImageLoader private constructor(val context: Context, okHttpClient: OkHttpClient?) : ImageLoader { private val mRequestManager: RequestManager @@ -67,7 +68,7 @@ open class GlideImageLoader private constructor(val context: Context, okHttpClie override fun cleanCache() { Glide.get(context).clearMemory() - Thread(Runnable { Glide.get(context).clearDiskCache() }).start() + Thread { Glide.get(context).clearDiskCache() }.start() } private fun downloadImageInto(uri: Uri?, target: Target, onlyRetrieveFromCache: Boolean) { diff --git a/README.md b/README.md index d7a8a91..41fbded 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [English](https://github.com/MikaelZero/mojito/blob/master/README_en.md) - ## 功能列表 - 支持Coil图片加载器 @@ -23,12 +22,9 @@ ## 动图效果 - - - # 开始 ------ @@ -54,24 +50,23 @@ implementation "com.github.mikaelzero.mojito:GlideImageLoader:$mojito_version" implementation "com.github.mikaelzero.mojito:FrescoImageLoader:$mojito_version" ``` - ## 初始化 ```kotlin // in your application Mojito.initialize( - GlideImageLoader.with(this), - SketchImageLoadFactory() - ) + GlideImageLoader.with(this), + SketchImageLoadFactory() +) //or //YourMojitoConfig:IMojitoConfig Mojito.initialize( - GlideImageLoader.with(this), - SketchImageLoadFactory(), - YourMojitoConfig() - ) + GlideImageLoader.with(this), + SketchImageLoadFactory(), + YourMojitoConfig() +) ``` ## 开始使用 @@ -88,57 +83,46 @@ Mojito.with(context) ## RecyclerView ```kotlin -Mojito.with(context) - .urls(SourceUtil.getNormalImages()) - .position(position) - .views(recyclerView, R.id.srcImageView) - .autoLoadTarget(false) - .setProgressLoader(object : InstanceLoader { - override fun providerInstance(): IProgress { - return DefaultPercentProgress() - } - }) - .setOnMojitoListener(object : SimpleMojitoViewCallback() { - override fun onLongClick(fragmentActivity: FragmentActivity?, view: View, x: Float, y: Float, position: Int) { - Toast.makeText(context, "long click", Toast.LENGTH_SHORT).show() - } - - override fun onClick(view: View, x: Float, y: Float, position: Int) { +binding.recyclerView.mojito(R.id.srcImageView) { + urls(SourceUtil.getNormalImages()) + position(position) + mojitoListener( + onClick = { view, x, y, pos -> Toast.makeText(context, "tap click", Toast.LENGTH_SHORT).show() - } - }) - .setIndicator(NumIndicator()) - .start() + } + ) + progressLoader { + DefaultPercentProgress() + } + setIndicator(NumIndicator()) +} ``` ## 单个 View ```kotlin - Mojito.with(context) - .urls(SourceUtil.getSingleImage()) - .views(singleIv) - .start() +binding.longHorIv.mojito(SourceUtil.getLongHorImage()) ``` ## 无 View ```kotlin - Mojito.with(context) - .urls(SourceUtil.getNormalImages()) - .start() + Mojito.start(context) { + urls(SourceUtil.getNormalImages()) +} ``` ## 视频 View or 视频/图片 混合View ```kotlin -Mojito.with(context) - .urls(SourceUtil.getVideoImages(), SourceUtil.getVideoTargetImages()) - .setMultiTargetEnableLoader(object : MultiTargetEnableLoader { +Mojito.start(context) { + urls(SourceUtil.getVideoImages(), SourceUtil.getVideoTargetImages()) + setMultiTargetEnableLoader(object : MultiTargetEnableLoader { override fun providerEnable(position: Int): Boolean { return position != 1 } }) - .setMultiContentLoader(object : MultiContentLoader { + setMultiContentLoader(object : MultiContentLoader { override fun providerLoader(position: Int): ImageViewLoadFactory { return if (position == 1) { ArtLoadFactory() @@ -147,9 +131,9 @@ Mojito.with(context) } } }) - .position(position) - .views(recyclerView, R.id.srcImageView) - .start() + position(position) + views(recyclerView, R.id.srcImageView) +} ``` ## Callback回调 @@ -192,11 +176,10 @@ Mojito.with(context) | views| 1. recylclerView,imageViewId
2. single view
3. multi views| | autoLoadTarget | 默认为true,如果你设置了原图的url并且设置了autoLoadTarget(false)
你需要使用setFragmentCoverLoader来自定义view| | setProgressLoader| 当你设置了 autoLoadTarget false 才会生效| -| setIndicator | 可以选择 NumIndicator 或者 CircleIndexIndicator| +| setIndicator | 可以选择 NumIndicator 或者 CircleIndexIndicator| | setActivityCoverLoader | 自定义Activity的覆盖层view| |setMultiContentLoader | 如果使用视频和图片混合模式,需要设置 ImageViewLoadFactory| - ## Thanks [sketch](https://github.com/panpf/sketch) diff --git a/README_en.md b/README_en.md index 1f9ba65..a204c5d 100644 --- a/README_en.md +++ b/README_en.md @@ -10,12 +10,9 @@ ## GIf Preview - - - # Getting started ------ @@ -41,24 +38,23 @@ implementation "com.github.mikaelzero.mojito:GlideImageLoader:$mojito_version" implementation "com.github.mikaelzero.mojito:FrescoImageLoader:$mojito_version" ``` - ## Initialize ```kotlin // in your application Mojito.initialize( - GlideImageLoader.with(this), - SketchImageLoadFactory() - ) + GlideImageLoader.with(this), + SketchImageLoadFactory() +) //or //YourMojitoConfig:IMojitoConfig Mojito.initialize( - GlideImageLoader.with(this), - SketchImageLoadFactory(), - YourMojitoConfig() - ) + GlideImageLoader.with(this), + SketchImageLoadFactory(), + YourMojitoConfig() +) ``` ## Start @@ -75,57 +71,46 @@ Mojito.with(context) ## RecyclerView ```kotlin -Mojito.with(context) - .urls(SourceUtil.getNormalImages()) - .position(position) - .views(recyclerView, R.id.srcImageView) - .autoLoadTarget(false) - .setProgressLoader(object : InstanceLoader { - override fun providerInstance(): IProgress { - return DefaultPercentProgress() - } - }) - .setOnMojitoListener(object : SimpleMojitoViewCallback() { - override fun onLongClick(fragmentActivity: FragmentActivity?, view: View, x: Float, y: Float, position: Int) { - Toast.makeText(context, "long click", Toast.LENGTH_SHORT).show() - } - - override fun onClick(view: View, x: Float, y: Float, position: Int) { +binding.recyclerView.mojito(R.id.srcImageView) { + urls(SourceUtil.getNormalImages()) + position(position) + mojitoListener( + onClick = { view, x, y, pos -> Toast.makeText(context, "tap click", Toast.LENGTH_SHORT).show() - } - }) - .setIndicator(NumIndicator()) - .start() + } + ) + progressLoader { + DefaultPercentProgress() + } + setIndicator(NumIndicator()) +} ``` ## Single View ```kotlin - Mojito.with(context) - .urls(SourceUtil.getSingleImage()) - .views(singleIv) - .start() +binding.longHorIv.mojito(SourceUtil.getLongHorImage()) ``` ## No View ```kotlin - Mojito.with(context) - .urls(SourceUtil.getNormalImages()) - .start() + Mojito.start(context) { + urls(SourceUtil.getNormalImages()) +} ``` ## Video View or Video/Image View ```kotlin -Mojito.with(context) - .urls(SourceUtil.getVideoImages(), SourceUtil.getVideoTargetImages()) - .setMultiTargetEnableLoader(object : MultiTargetEnableLoader { +Mojito.start(context) { + urls(SourceUtil.getVideoImages(), SourceUtil.getVideoTargetImages()) + setMultiTargetEnableLoader(object : MultiTargetEnableLoader { override fun providerEnable(position: Int): Boolean { return position != 1 } }) - .setMultiContentLoader(object : MultiContentLoader { + setMultiContentLoader(object : MultiContentLoader { override fun providerLoader(position: Int): ImageViewLoadFactory { return if (position == 1) { ArtLoadFactory() @@ -134,9 +119,9 @@ Mojito.with(context) } } }) - .position(position) - .views(recyclerView, R.id.srcImageView) - .start() + position(position) + views(recyclerView, R.id.srcImageView) +} ``` ## Callback @@ -183,7 +168,6 @@ Mojito.with(context) | setActivityCoverLoader | custom cover layout| |setMultiContentLoader | if you need both of video and image ,provider different ImageViewLoadFactory| - ## Thanks [sketch](https://github.com/panpf/sketch) diff --git a/SketchImageViewLoader/build.gradle b/SketchImageViewLoader/build.gradle deleted file mode 100644 index caba2eb..0000000 --- a/SketchImageViewLoader/build.gradle +++ /dev/null @@ -1,43 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'com.github.dcendents.android-maven' -group = 'com.github.mikaelzero' -android { - def globalConfiguration = rootProject.extensions.getByName("ext") - compileSdkVersion globalConfiguration.androidCompileSdkVersion - - defaultConfig { - minSdkVersion globalConfiguration.androidMinSdkVersion - targetSdkVersion globalConfiguration.androidTargetSdkVersion - versionCode 1 - versionName "1.0" - consumerProguardFiles "consumer-rules.pro" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - buildToolsVersion '30.0.3' -} - -dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.5.0' - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation 'me.panpf:sketch-gif:2.7.1' - implementation 'androidx.exifinterface:exifinterface:1.3.2' - implementation project(':mojito') -} - diff --git a/SketchImageViewLoader/build.gradle.kts b/SketchImageViewLoader/build.gradle.kts new file mode 100644 index 0000000..3805536 --- /dev/null +++ b/SketchImageViewLoader/build.gradle.kts @@ -0,0 +1,25 @@ +import mojito.setupLibraryModule + +plugins { + id("com.android.library") + id("kotlin-android") + id("com.github.dcendents.android-maven") +} + +group = "com.github.mikaelzero" +setupLibraryModule { + defaultConfig { + minSdk = 16 + } +} + +dependencies { + implementation(mojito.Library.KOTLINX_STDLIB) + implementation(mojito.Library.ANDROIDX_APPCOMPAT) + implementation(mojito.Library.ANDROIDX_CORE) + implementation(mojito.Library.OKHTTP) + implementation("me.panpf:sketch-gif:2.7.1") + implementation("androidx.exifinterface:exifinterface:1.3.2") + implementation(project(":mojito")) +} + diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 31eafe0..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,57 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' - -android { - def globalConfiguration = rootProject.extensions.getByName("ext") - compileSdkVersion globalConfiguration.androidCompileSdkVersion - defaultConfig { - applicationId "net.mikaelzero.app" - minSdkVersion 21 - targetSdkVersion globalConfiguration.androidTargetSdkVersion - versionCode 5 - versionName "5" - multiDexEnabled true - } - buildTypes { - debug { - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - debuggable true - } - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - buildToolsVersion '30.0.3' -} - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.multidex:multidex:2.0.1' - implementation 'com.google.android.material:material:1.4.0' - implementation 'com.github.bumptech.glide:glide:4.11.0' - implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4' - implementation 'com.gyf.immersionbar:immersionbar:3.0.0' - implementation "com.daimajia.swipelayout:library:1.2.0@aar" - implementation "com.facebook.fresco:fresco:2.1.0" - implementation 'org.salient.artvideoplayer:artplayer-core:1.1.0' - implementation 'org.salient.artvideoplayer:artplayer-ijk:1.1.0' - implementation "org.salient.artvideoplayer:artplayer-armv7a:1.1.0" - implementation("io.coil-kt:coil:1.3.0") - - implementation project(':mojito') - implementation project(':GlideImageLoader') - implementation project(':FrescoImageLoader') - implementation project(':SketchImageViewLoader') - implementation project(':coilimageloader') -} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..5d561a7 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,55 @@ +import mojito.Library +import mojito.setupAppModule + +plugins { + id("com.android.application") + id("kotlin-android") + id("kotlin-parcelize") +} +setupAppModule { + defaultConfig { + minSdk = 21 + applicationId = "net.mikaelzero.app" + multiDexEnabled = true + buildFeatures { + viewBinding = true + } + } + buildTypes { + getByName("release") { + isMinifyEnabled = true + isShrinkResources = true + proguardFiles("proguard-rules.pro") + } + } +} + +dependencies { + + implementation(Library.KOTLINX_STDLIB) + + implementation(Library.ANDROIDX_ACTIVITY) + implementation(Library.ANDROIDX_APPCOMPAT) + implementation(Library.ANDROIDX_CONSTRAINT_LAYOUT) + implementation(Library.ANDROIDX_CORE) + implementation(Library.ANDROIDX_LIFECYCLE_VIEW_MODEL) + implementation(Library.ANDROIDX_MULTIDEX) + implementation(Library.ANDROIDX_RECYCLER_VIEW) + implementation(Library.MATERIAL) + + implementation(Library.GLIDE) + implementation(Library.BASE_ADAPTER) + implementation(Library.IMMERSIONBAR) + implementation(Library.SWIPELAYOUT) + implementation(Library.FRESCO) + implementation(Library.ART_PLAY_CORE) + implementation(Library.ART_PLAY_IJK) + implementation(Library.ART_PLAY_V7A) + implementation(Library.COIL) + + implementation(project(":mojito")) + implementation(project(":GlideImageLoader")) + implementation(project(":FrescoImageLoader")) + implementation(project(":SketchImageViewLoader")) + implementation(project(":coilimageloader")) +} diff --git a/app/src/main/java/net/mikaelzero/app/ActivityCoverActivity.kt b/app/src/main/java/net/mikaelzero/app/ActivityCoverActivity.kt index e2cf85e..32ea3df 100644 --- a/app/src/main/java/net/mikaelzero/app/ActivityCoverActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/ActivityCoverActivity.kt @@ -4,43 +4,38 @@ import android.content.Context import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager -import kotlinx.android.synthetic.main.activity_target.* +import net.mikaelzero.app.databinding.ActivityCoverBinding import net.mikaelzero.mojito.Mojito import net.mikaelzero.mojito.impl.DefaultPercentProgress import net.mikaelzero.mojito.impl.DefaultTargetFragmentCover -import net.mikaelzero.mojito.interfaces.IProgress -import net.mikaelzero.mojito.loader.FragmentCoverLoader -import net.mikaelzero.mojito.loader.InstanceLoader class ActivityCoverActivity : AppCompatActivity() { var context: Context? = null - + private lateinit var binding: ActivityCoverBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) context = this - setContentView(R.layout.activity_cover) - recyclerView.layoutManager = GridLayoutManager(this, 3) + binding = ActivityCoverBinding.inflate(layoutInflater) + setContentView(binding.root) + binding.recyclerView.layoutManager = GridLayoutManager(this, 3) val adapter = ImageAdapter() adapter.setList(SourceUtil.getTargetButtonSmall()) - recyclerView.adapter = adapter + binding.recyclerView.adapter = adapter adapter.setOnItemClickListener { adapter, view, position -> - Mojito.with(context) - .urls(SourceUtil.getTargetButtonSmall(), SourceUtil.getTargetButtonTarget()) - .position(position) - .views(recyclerView, R.id.srcImageView) - .autoLoadTarget(false) - .setActivityCoverLoader(BilibiliActivityCoverLoader()) - .setFragmentCoverLoader(object : InstanceLoader { - override fun providerInstance(): FragmentCoverLoader { - return DefaultTargetFragmentCover() - } - }) - .setProgressLoader(object : InstanceLoader { - override fun providerInstance(): IProgress { - return DefaultPercentProgress() - } - }) - .start() + Mojito.start(this) { + urls(SourceUtil.getTargetButtonSmall(), SourceUtil.getTargetButtonTarget()) + position(position) + views(binding.recyclerView, R.id.srcImageView) + autoLoadTarget(false) + setActivityCoverLoader(BilibiliActivityCoverLoader()) + fragmentCoverLoader { + DefaultTargetFragmentCover() + } + progressLoader { + DefaultPercentProgress() + } + } + } } diff --git a/app/src/main/java/net/mikaelzero/app/DifferentScenesActivity.kt b/app/src/main/java/net/mikaelzero/app/DifferentScenesActivity.kt index d5f0190..a97fbf4 100644 --- a/app/src/main/java/net/mikaelzero/app/DifferentScenesActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/DifferentScenesActivity.kt @@ -5,18 +5,19 @@ import android.os.Bundle import android.view.LayoutInflater import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager -import kotlinx.android.synthetic.main.activity_different_scenes.* +import net.mikaelzero.app.databinding.ActivityDifferentScenesBinding import net.mikaelzero.mojito.Mojito import net.mikaelzero.mojito.impl.NumIndicator class DifferentScenesActivity : AppCompatActivity() { var context: Context? = null - + private lateinit var binding: ActivityDifferentScenesBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) context = this - setContentView(R.layout.activity_different_scenes) - recyclerView.layoutManager = GridLayoutManager(this, 3) + binding = ActivityDifferentScenesBinding.inflate(layoutInflater) + setContentView(binding.root) + binding.recyclerView.layoutManager = GridLayoutManager(this, 3) val adapter = DifferentScenesAdapter() val list = mutableListOf() list.add(UrlBean("", 0)) @@ -25,7 +26,7 @@ class DifferentScenesActivity : AppCompatActivity() { list.add(UrlBean(s, 1)) } adapter.setList(list) - recyclerView.adapter = adapter + binding.recyclerView.adapter = adapter val newUrls = mutableListOf() newUrls.add("") newUrls.add("") @@ -34,12 +35,13 @@ class DifferentScenesActivity : AppCompatActivity() { if (position == 0) { return@setOnItemClickListener } - Mojito.with(context) - .urls(newUrls) - .position(position, headerSize = adapter.headerLayoutCount, footerSize = adapter.footerLayoutCount) - .views(recyclerView, R.id.srcImageView) - .setIndicator(NumIndicator()) - .start() + Mojito.start(context) { + urls(newUrls) + position(position, headerSize = adapter.headerLayoutCount, footerSize = adapter.footerLayoutCount) + views(binding.recyclerView, R.id.srcImageView) + setIndicator(NumIndicator()) + } + } adapter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.header_layout, null)) adapter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.header_layout, null)) diff --git a/app/src/main/java/net/mikaelzero/app/MainActivity.kt b/app/src/main/java/net/mikaelzero/app/MainActivity.kt index bca8b9b..d44d885 100644 --- a/app/src/main/java/net/mikaelzero/app/MainActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/MainActivity.kt @@ -4,7 +4,11 @@ import android.content.Context import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import kotlinx.android.synthetic.main.activity_main.* +import coil.imageLoader +import coil.util.CoilUtils +import com.bumptech.glide.Glide +import com.facebook.drawee.backends.pipeline.Fresco +import net.mikaelzero.app.databinding.ActivityMainBinding import net.mikaelzero.app.local.LocalImageActivity import net.mikaelzero.app.stagger.StaggerActivity import net.mikaelzero.app.video.VideoActivity @@ -59,12 +63,15 @@ class MainActivity : AppCompatActivity() { var startType: StartType = StartType.Normal + private lateinit var binding: ActivityMainBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) setImageLoader(applicationContext, LoaderType.Coil) - coil.isChecked = true - loaderRb.setOnCheckedChangeListener { group, checkedId -> + binding.coil.isChecked = true + binding.loaderRb.setOnCheckedChangeListener { group, checkedId -> when (checkedId) { R.id.coil -> { setImageLoader(applicationContext, LoaderType.Coil) @@ -77,8 +84,8 @@ class MainActivity : AppCompatActivity() { } } } - normal.isChecked = true - functionRg.setOnCheckedChangeListener { group, checkedId -> + binding.normal.isChecked = true + binding.functionRg.setOnCheckedChangeListener { group, checkedId -> when (checkedId) { R.id.normal -> { startType = StartType.Normal @@ -103,7 +110,7 @@ class MainActivity : AppCompatActivity() { } } } - startFb.setOnClickListener { + binding.startFb.setOnClickListener { when (startType) { StartType.Normal -> { startActivity(Intent(this@MainActivity, PreviewActivity::class.java)) @@ -128,9 +135,17 @@ class MainActivity : AppCompatActivity() { } } } - cacheBt.setOnClickListener { + binding.cacheBt.setOnClickListener { + imageLoader.memoryCache.clear() + CoilUtils.createDefaultCache(this).directory.delete() CoilImageLoader.with(applicationContext).cleanCache() + Glide.get(this).clearMemory() + Thread { Glide.get(this).clearDiskCache() }.start() GlideImageLoader.with(applicationContext).cleanCache() + val imagePipeline = Fresco.getImagePipeline() + imagePipeline.clearMemoryCaches() + imagePipeline.clearDiskCaches() + imagePipeline.clearCaches() FrescoImageLoader.with(applicationContext).cleanCache() } } diff --git a/app/src/main/java/net/mikaelzero/app/PreviewActivity.kt b/app/src/main/java/net/mikaelzero/app/PreviewActivity.kt index 59158c0..d4fecd9 100644 --- a/app/src/main/java/net/mikaelzero/app/PreviewActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/PreviewActivity.kt @@ -3,112 +3,77 @@ package net.mikaelzero.app import android.content.Context import android.os.Bundle import android.view.LayoutInflater -import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.FragmentActivity import androidx.recyclerview.widget.GridLayoutManager -import kotlinx.android.synthetic.main.activity_display.* +import net.mikaelzero.app.databinding.ActivityDisplayBinding import net.mikaelzero.mojito.Mojito -import net.mikaelzero.mojito.MojitoView +import net.mikaelzero.mojito.ext.mojito import net.mikaelzero.mojito.impl.DefaultPercentProgress import net.mikaelzero.mojito.impl.NumIndicator -import net.mikaelzero.mojito.impl.SimpleMojitoViewCallback import net.mikaelzero.mojito.interfaces.IProgress import net.mikaelzero.mojito.loader.InstanceLoader class PreviewActivity : AppCompatActivity() { var context: Context? = null - + private lateinit var binding: ActivityDisplayBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) context = this - setContentView(R.layout.activity_display) - recyclerView.layoutManager = GridLayoutManager(this, 3) + binding = ActivityDisplayBinding.inflate(layoutInflater) + setContentView(binding.root) + binding.recyclerView.layoutManager = GridLayoutManager(this, 3) val adapter = ImageAdapter() adapter.setList(SourceUtil.getNormalImages()) - recyclerView.adapter = adapter + binding.recyclerView.adapter = adapter adapter.setOnItemClickListener { _, view, position -> - Mojito.with(context) - .urls(SourceUtil.getNormalImages()) - .position(position, headerSize = 1, footerSize = 1) - .views(recyclerView, R.id.srcImageView) - .autoLoadTarget(false) - .setProgressLoader(object : InstanceLoader { + + binding.recyclerView.mojito(R.id.srcImageView) { + urls(SourceUtil.getNormalImages()) + position(position, headerSize = 1, footerSize = 1) + autoLoadTarget(false) + setProgressLoader(object : InstanceLoader { override fun providerInstance(): IProgress { return DefaultPercentProgress() } }) - .setOnMojitoListener(object : SimpleMojitoViewCallback() { - override fun onLongClick(fragmentActivity: FragmentActivity?, view: View, x: Float, y: Float, position: Int) { - Toast.makeText(context, "long click", Toast.LENGTH_SHORT).show() - } - - override fun onClick(view: View, x: Float, y: Float, position: Int) { + mojitoListener( + onClick = { view, x, y, pos -> Toast.makeText(context, "tap click", Toast.LENGTH_SHORT).show() } - - override fun onStartAnim(position: Int) { - - } - - override fun onShowFinish(mojitoView: MojitoView, showImmediately: Boolean) { -// recyclerView.getChildAt(position + 1).findViewById(R.id.srcImageView)?.visibility = View.GONE - } - - override fun onMojitoViewFinish(pagePosition: Int) { -// for (x in 0 until recyclerView.childCount) { -// recyclerView.getChildAt(x).findViewById(R.id.srcImageView)?.visibility = View.VISIBLE -// } - } - - override fun onViewPageSelected(position: Int) { -// for (x in 0 until recyclerView.childCount) { -// if ((position + 1) == x) { -// recyclerView.getChildAt(x).findViewById(R.id.srcImageView)?.visibility = View.GONE -// } else { -// recyclerView.getChildAt(x).findViewById(R.id.srcImageView)?.visibility = View.VISIBLE -// } -// } - } - }) - .setIndicator(NumIndicator()) - .start() + ) + progressLoader { + DefaultPercentProgress() + } + setIndicator(NumIndicator()) + } } adapter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.header_layout, null)) adapter.addFooterView(LayoutInflater.from(this).inflate(R.layout.header_layout, null)) - singleIv.addImg(SourceUtil.getSingleImage()) - longHorIv.addImg(SourceUtil.getLongHorImage()) + binding.singleIv.addImg(SourceUtil.getSingleImage()) + binding.longHorIv.addImg(SourceUtil.getLongHorImage()) - singleIv.setOnClickListener { - Mojito.with(context) - .urls(SourceUtil.getSingleImage()) - .views(singleIv) - .setOnMojitoListener(object : SimpleMojitoViewCallback() { - override fun onLongClick(fragmentActivity: FragmentActivity?, view: View, x: Float, y: Float, position: Int) { - Toast.makeText(fragmentActivity, "long click", Toast.LENGTH_SHORT).show() - } - }) - .start() + binding.singleIv.setOnClickListener { + Mojito.start(this) { + urls(SourceUtil.getSingleImage()) + views(binding.singleIv) + } } - longHorIv.setOnClickListener { - Mojito.with(context) - .urls(SourceUtil.getLongHorImage()) - .views(longHorIv) - .start() + binding.longHorIv.setOnClickListener { + binding.longHorIv.mojito(SourceUtil.getLongHorImage()) } - noViewBtn.setOnClickListener { - Mojito.with(context) - .urls(SourceUtil.getSingleImage()) - .start() + binding.noViewBtn.setOnClickListener { + Mojito.start(this) { + urls(SourceUtil.getSingleImage()) + } } - noViewViewPagerBtn.setOnClickListener { - Mojito.with(context) - .urls(SourceUtil.getNormalImages()) - .setIndicator(NumIndicator()) - .start() + binding.noViewViewPagerBtn.setOnClickListener { + Mojito.start(this) { + urls(SourceUtil.getNormalImages()) + .setIndicator(NumIndicator()) + } } } } \ No newline at end of file diff --git a/app/src/main/java/net/mikaelzero/app/TargetActivity.kt b/app/src/main/java/net/mikaelzero/app/TargetActivity.kt index 7a126ed..7715ea4 100644 --- a/app/src/main/java/net/mikaelzero/app/TargetActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/TargetActivity.kt @@ -4,44 +4,39 @@ import android.content.Context import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager -import kotlinx.android.synthetic.main.activity_target.* +import net.mikaelzero.app.databinding.ActivityTargetBinding import net.mikaelzero.mojito.Mojito import net.mikaelzero.mojito.impl.DefaultPercentProgress import net.mikaelzero.mojito.impl.DefaultTargetFragmentCover import net.mikaelzero.mojito.impl.NumIndicator -import net.mikaelzero.mojito.interfaces.IProgress -import net.mikaelzero.mojito.loader.FragmentCoverLoader -import net.mikaelzero.mojito.loader.InstanceLoader class TargetActivity : AppCompatActivity() { var context: Context? = null - + private lateinit var binding: ActivityTargetBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) context = this - setContentView(R.layout.activity_target) - recyclerView.layoutManager = GridLayoutManager(this, 3) + binding = ActivityTargetBinding.inflate(layoutInflater) + setContentView(binding.root) + binding.recyclerView.layoutManager = GridLayoutManager(this, 3) val adapter = ImageAdapter() adapter.setList(SourceUtil.getTargetButtonSmall()) - recyclerView.adapter = adapter + binding.recyclerView.adapter = adapter adapter.setOnItemClickListener { adapter, view, position -> - Mojito.with(context) - .urls(SourceUtil.getTargetButtonSmall(), SourceUtil.getTargetButtonTarget()) - .position(position) - .views(recyclerView, R.id.srcImageView) - .autoLoadTarget(false) - .setFragmentCoverLoader(object : InstanceLoader { - override fun providerInstance(): FragmentCoverLoader { - return DefaultTargetFragmentCover() - } - }) - .setProgressLoader(object : InstanceLoader { - override fun providerInstance(): IProgress { - return DefaultPercentProgress() - } - }) - .setIndicator(NumIndicator()) - .start() + Mojito.start(context) { + urls(SourceUtil.getTargetButtonSmall(), SourceUtil.getTargetButtonTarget()) + position(position) + views(binding.recyclerView, R.id.srcImageView) + autoLoadTarget(false) + fragmentCoverLoader { + DefaultTargetFragmentCover() + } + progressLoader { + DefaultPercentProgress() + } + setIndicator(NumIndicator()) + } + } } diff --git a/app/src/main/java/net/mikaelzero/app/local/LocalImageActivity.kt b/app/src/main/java/net/mikaelzero/app/local/LocalImageActivity.kt index 8888062..7a44337 100644 --- a/app/src/main/java/net/mikaelzero/app/local/LocalImageActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/local/LocalImageActivity.kt @@ -8,9 +8,9 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.recyclerview.widget.GridLayoutManager -import kotlinx.android.synthetic.main.activity_local.* import net.mikaelzero.app.R import net.mikaelzero.app.SourceUtil +import net.mikaelzero.app.databinding.ActivityLocalBinding import net.mikaelzero.mojito.Mojito import net.mikaelzero.mojito.impl.NumIndicator @@ -22,9 +22,11 @@ import net.mikaelzero.mojito.impl.NumIndicator class LocalImageActivity : AppCompatActivity() { private var images: List? = null + private lateinit var binding: ActivityLocalBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_local) + binding = ActivityLocalBinding.inflate(layoutInflater) + setContentView(binding.root) if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, @@ -41,15 +43,16 @@ class LocalImageActivity : AppCompatActivity() { if (images != null && !images.isNullOrEmpty()) { val localAdapter = LocalImageAdapter() localAdapter.setList(images) - recyclerView.adapter = localAdapter - recyclerView.layoutManager = GridLayoutManager(this, 3) + binding.recyclerView.adapter = localAdapter + binding.recyclerView.layoutManager = GridLayoutManager(this, 3) localAdapter.setOnItemClickListener { adapter, view, position -> - Mojito.with(this) - .urls(images) - .position(position) - .views(recyclerView, R.id.srcImageView) - .setIndicator(NumIndicator()) - .start() + Mojito.start(this) { + urls(images) + position(position) + views(binding.recyclerView, R.id.srcImageView) + setIndicator(NumIndicator()) + } + } } } diff --git a/app/src/main/java/net/mikaelzero/app/stagger/StaggerActivity.kt b/app/src/main/java/net/mikaelzero/app/stagger/StaggerActivity.kt index 40b18c6..1383a00 100644 --- a/app/src/main/java/net/mikaelzero/app/stagger/StaggerActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/stagger/StaggerActivity.kt @@ -3,12 +3,10 @@ package net.mikaelzero.app.stagger import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.StaggeredGridLayoutManager -import kotlinx.android.synthetic.main.activity_stagger.* import net.mikaelzero.app.R import net.mikaelzero.app.SourceUtil +import net.mikaelzero.app.databinding.ActivityStaggerBinding import net.mikaelzero.mojito.Mojito -import net.mikaelzero.mojito.loader.glide.GlideImageLoader -import net.mikaelzero.mojito.view.sketch.SketchImageLoadFactory /** * @Author: MikaelZero @@ -16,19 +14,22 @@ import net.mikaelzero.mojito.view.sketch.SketchImageLoadFactory * @Description: */ class StaggerActivity : AppCompatActivity() { + private lateinit var binding: ActivityStaggerBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_stagger) - recyclerView.layoutManager = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL) + binding = ActivityStaggerBinding.inflate(layoutInflater) + setContentView(binding.root) + binding.recyclerView.layoutManager = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL) val adapter = StaggerAdapter() - recyclerView.adapter = adapter + binding.recyclerView.adapter = adapter adapter.setList(SourceUtil.getNormalImages()) adapter.setOnItemClickListener { adapter, view, position -> - Mojito.with(this) - .urls(SourceUtil.getNormalImages()) - .position(position) - .views(recyclerView, R.id.srcImageView) - .start() + Mojito.start(this) { + urls(SourceUtil.getNormalImages()) + position(position) + views(binding.recyclerView, R.id.srcImageView) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/net/mikaelzero/app/video/VideoActivity.kt b/app/src/main/java/net/mikaelzero/app/video/VideoActivity.kt index e9cf36e..99a6b27 100644 --- a/app/src/main/java/net/mikaelzero/app/video/VideoActivity.kt +++ b/app/src/main/java/net/mikaelzero/app/video/VideoActivity.kt @@ -5,12 +5,11 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager import com.gyf.immersionbar.ImmersionBar -import kotlinx.android.synthetic.main.activity_target.recyclerView -import kotlinx.android.synthetic.main.activity_video.* import net.mikaelzero.app.ImageAdapter import net.mikaelzero.app.R import net.mikaelzero.app.SourceUtil import net.mikaelzero.app.addImg +import net.mikaelzero.app.databinding.ActivityVideoBinding import net.mikaelzero.mojito.Mojito import net.mikaelzero.mojito.interfaces.ImageViewLoadFactory import net.mikaelzero.mojito.loader.MultiContentLoader @@ -18,20 +17,21 @@ import net.mikaelzero.mojito.view.sketch.SketchImageLoadFactory class VideoActivity : AppCompatActivity() { var context: Context? = null - + private lateinit var binding: ActivityVideoBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) context = this - setContentView(R.layout.activity_video) + binding = ActivityVideoBinding.inflate(layoutInflater) + setContentView(binding.root) ImmersionBar.with(this).transparentBar().init() - singleVideoIv.addImg(SourceUtil.getSingleVideoImages()) + binding.singleVideoIv.addImg(SourceUtil.getSingleVideoImages()) - singleVideoIv.setOnClickListener { - Mojito.with(context) - .urls(SourceUtil.getSingleVideoImages(), SourceUtil.getSingleVideoTargetImages()) - .setMultiContentLoader(object : MultiContentLoader { + binding.singleVideoIv.setOnClickListener { + Mojito.start(context) { + urls(SourceUtil.getSingleVideoImages(), SourceUtil.getSingleVideoTargetImages()) + setMultiContentLoader(object : MultiContentLoader { override fun providerLoader(position: Int): ImageViewLoadFactory { return ArtLoadFactory() } @@ -40,17 +40,18 @@ class VideoActivity : AppCompatActivity() { return false } }) - .views(singleVideoIv) - .start() + views(binding.singleVideoIv) + } + } - recyclerView.layoutManager = GridLayoutManager(this, 3) + binding.recyclerView.layoutManager = GridLayoutManager(this, 3) val adapter = ImageAdapter() adapter.setList(SourceUtil.getVideoImages()) - recyclerView.adapter = adapter - adapter.setOnItemClickListener { adapter, view, position -> - Mojito.with(context) - .urls(SourceUtil.getVideoImages(), SourceUtil.getVideoTargetImages()) - .setMultiContentLoader(object : MultiContentLoader { + binding.recyclerView.adapter = adapter + adapter.setOnItemClickListener { _, view, position -> + Mojito.start(context) { + urls(SourceUtil.getVideoImages(), SourceUtil.getVideoTargetImages()) + setMultiContentLoader(object : MultiContentLoader { override fun providerLoader(position: Int): ImageViewLoadFactory { return if (position == 1 || position == 2) { ArtLoadFactory() @@ -63,9 +64,10 @@ class VideoActivity : AppCompatActivity() { return position == 0 || position == 3 } }) - .position(position) - .views(recyclerView, R.id.srcImageView) - .start() + position(position) + views(binding.recyclerView, R.id.srcImageView) + } + } } diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 7a540af..0000000 --- a/build.gradle +++ /dev/null @@ -1,36 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - ext { - kotlin_version = '1.5.21' - mojito_version = '1.8.0' - } - - repositories { - google() - maven { url "https://jitpack.io" } - mavenCentral() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' - } -} - -allprojects { - repositories { - google() - maven { url "https://jitpack.io" } - mavenCentral() - jcenter() - } -} - -ext { - //Android - androidMinSdkVersion = 16 - androidTargetSdkVersion = 29 - androidCompileSdkVersion = 29 -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..37dc220 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,26 @@ +buildscript { + apply(from = "buildSrc/plugins.gradle.kts") + repositories { + google() + maven("https://jitpack.io") + mavenCentral() + gradlePluginPortal() + } + dependencies { + classpath(rootProject.extra["androidPlugin"].toString()) + classpath(rootProject.extra["kotlinPlugin"].toString()) + classpath(rootProject.extra["mavenPublishPlugin"].toString()) + } +} +tasks.register(name = "clean") { + group = "build" + delete(rootProject.buildDir) +} +allprojects { + repositories { + google() + maven("https://jitpack.io") + mavenCentral() + gradlePluginPortal() + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..e3ac275 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + `kotlin-dsl` +} + +repositories { + google() + mavenCentral() +} + +apply(from = "plugins.gradle.kts") + +dependencies { + implementation(rootProject.extra["androidPlugin"].toString()) + implementation(rootProject.extra["kotlinPlugin"].toString()) +} diff --git a/buildSrc/plugins.gradle.kts b/buildSrc/plugins.gradle.kts new file mode 100644 index 0000000..f4f1155 --- /dev/null +++ b/buildSrc/plugins.gradle.kts @@ -0,0 +1,5 @@ +rootProject.extra.apply { + set("androidPlugin", "com.android.tools.build:gradle:4.2.2") + set("kotlinPlugin", "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21") + set("mavenPublishPlugin", "com.github.dcendents:android-maven-gradle-plugin:2.1") +} diff --git a/buildSrc/src/main/kotlin/Extensions.kt b/buildSrc/src/main/kotlin/Extensions.kt new file mode 100644 index 0000000..5e57649 --- /dev/null +++ b/buildSrc/src/main/kotlin/Extensions.kt @@ -0,0 +1,101 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package mojito + +import org.gradle.api.Project +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.dsl.DependencyHandler +import org.gradle.api.provider.Property +import org.gradle.api.provider.SetProperty +import org.gradle.kotlin.dsl.kotlin +import org.gradle.kotlin.dsl.project +import kotlin.math.pow + +val Project.minSdk: Int + get() = intProperty("minSdk") + +val Project.targetSdk: Int + get() = intProperty("targetSdk") + +val Project.compileSdk: Int + get() = intProperty("compileSdk") + +val Project.groupId: String + get() = stringProperty("GROUP") + +val Project.versionName: String + get() = stringProperty("VERSION_NAME") + +val Project.versionCode: Int + get() = versionName + .takeWhile { it.isDigit() || it == '.' } + .split('.') + .map { it.toInt() } + .reversed() + .sumByIndexed { index, unit -> + // 1.2.3 -> 102030 + (unit * 10.0.pow(2 * index + 1)).toInt() + } + +private fun Project.intProperty(name: String): Int { + return (property(name) as String).toInt() +} + +private fun Project.stringProperty(name: String): String { + return property(name) as String +} + +private inline fun List.sumByIndexed(selector: (Int, T) -> Int): Int { + var index = 0 + var sum = 0 + for (element in this) { + sum += selector(index++, element) + } + return sum +} + +private fun DependencyHandler.testImplementation(dependencyNotation: Any): Dependency? { + return add("testImplementation", dependencyNotation) +} + +private fun DependencyHandler.androidTestImplementation(dependencyNotation: Any): Dependency? { + return add("androidTestImplementation", dependencyNotation) +} + +fun DependencyHandler.addTestDependencies(kotlinVersion: String) { + testImplementation(project(":coil-test")) + + testImplementation(Library.JUNIT) + testImplementation(kotlin("test-junit", kotlinVersion)) + + testImplementation(Library.KOTLINX_COROUTINES_TEST) + + testImplementation(Library.ANDROIDX_TEST_CORE) + testImplementation(Library.ANDROIDX_TEST_JUNIT) + testImplementation(Library.ANDROIDX_TEST_RULES) + testImplementation(Library.ANDROIDX_TEST_RUNNER) + + + testImplementation(Library.ROBOLECTRIC) +} + +fun DependencyHandler.addAndroidTestDependencies(kotlinVersion: String, includeTestProject: Boolean = true) { + if (includeTestProject) { + androidTestImplementation(project(":coil-test")) + } + + androidTestImplementation(Library.JUNIT) + androidTestImplementation(kotlin("test-junit", kotlinVersion)) + + androidTestImplementation(Library.ANDROIDX_APPCOMPAT) + androidTestImplementation(Library.MATERIAL) + + androidTestImplementation(Library.ANDROIDX_TEST_CORE) + androidTestImplementation(Library.ANDROIDX_TEST_JUNIT) + androidTestImplementation(Library.ANDROIDX_TEST_RULES) + androidTestImplementation(Library.ANDROIDX_TEST_RUNNER) +} + +inline infix fun Property.by(value: T) = set(value) + +inline infix fun SetProperty.by(value: Set) = set(value) diff --git a/buildSrc/src/main/kotlin/Library.kt b/buildSrc/src/main/kotlin/Library.kt new file mode 100644 index 0000000..8161b1f --- /dev/null +++ b/buildSrc/src/main/kotlin/Library.kt @@ -0,0 +1,68 @@ +@file:Suppress("unused", "SpellCheckingInspection") + +package mojito + +object Library { + + // CORE + + private const val COROUTINES_VERSION = "1.5.21" + const val KOTLINX_COROUTINES_ANDROID = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$COROUTINES_VERSION" + const val KOTLINX_STDLIB = "org.jetbrains.kotlin:kotlin-stdlib:$COROUTINES_VERSION" + + const val ANDROIDX_ACTIVITY = "androidx.activity:activity-ktx:1.2.4" + const val ANDROIDX_ANNOTATION = "androidx.annotation:annotation:1.2.0" + const val ANDROIDX_COLLECTION = "androidx.collection:collection-ktx:1.1.0" + const val ANDROIDX_CONSTRAINT_LAYOUT = "androidx.constraintlayout:constraintlayout:2.0.4" + const val ANDROIDX_CORE = "androidx.core:core-ktx:1.6.0" + const val ANDROIDX_EXIF_INTERFACE = "androidx.exifinterface:exifinterface:1.3.2" + const val ANDROIDX_MULTIDEX = "androidx.multidex:multidex:2.0.1" + const val ANDROIDX_RECYCLER_VIEW = "androidx.recyclerview:recyclerview:1.2.1" + const val ANDROIDX_VECTOR_DRAWABLE_ANIMATED = "androidx.vectordrawable:vectordrawable-animated:1.1.0" + + private const val APPCOMPAT_VERSION = "1.3.1" + const val ANDROIDX_APPCOMPAT = "androidx.appcompat:appcompat:$APPCOMPAT_VERSION" + const val ANDROIDX_APPCOMPAT_RESOURCES = "androidx.appcompat:appcompat-resources:$APPCOMPAT_VERSION" + + private const val LIFECYCLE_VERSION = "2.3.1" + const val ANDROIDX_LIFECYCLE_COMMON = "androidx.lifecycle:lifecycle-common-java8:$LIFECYCLE_VERSION" + const val ANDROIDX_LIFECYCLE_RUNTIME = "androidx.lifecycle:lifecycle-runtime:$LIFECYCLE_VERSION" + const val ANDROIDX_LIFECYCLE_VIEW_MODEL = "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" + + const val COMPOSE_VERSION = "1.0.0-rc02" + const val COMPOSE_FOUNDATION = "androidx.compose.foundation:foundation:$COMPOSE_VERSION" + const val COMPOSE_UI_TEST_JUNIT = "androidx.compose.ui:ui-test-junit4:$COMPOSE_VERSION" + const val COMPOSE_UI_TEST_MANIFEST = "androidx.compose.ui:ui-test-manifest:$COMPOSE_VERSION" + + const val MATERIAL = "com.google.android.material:material:1.4.0" + + const val ANDROID_SVG = "com.caverock:androidsvg-aar:1.4" + + const val OKHTTP = "com.squareup.okhttp3:okhttp:4.9.1" + + const val OKIO = "com.squareup.okio:okio:2.10.0" + + const val GLIDE = "com.github.bumptech.glide:glide:4.11.0" + const val BASE_ADAPTER = "com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4" + const val IMMERSIONBAR = "com.gyf.immersionbar:immersionbar:3.0.0" + const val SWIPELAYOUT = "com.daimajia.swipelayout:library:1.2.0@aar" + const val FRESCO = "com.facebook.fresco:fresco:2.1.0" + const val ART_PLAY_CORE = "org.salient.artvideoplayer:artplayer-core:1.1.0" + const val ART_PLAY_IJK = "org.salient.artvideoplayer:artplayer-ijk:1.1.0" + const val ART_PLAY_V7A = "org.salient.artvideoplayer:artplayer-armv7a:1.1.0" + const val COIL = "io.coil-kt:coil:1.3.0" + + // TEST + + const val JUNIT = "junit:junit:4.13.2" + + const val KOTLINX_COROUTINES_TEST = "org.jetbrains.kotlinx:kotlinx-coroutines-test:$COROUTINES_VERSION" + + private const val ANDROIDX_TEST_VERSION = "1.4.0" + const val ANDROIDX_TEST_CORE = "androidx.test:core-ktx:$ANDROIDX_TEST_VERSION" + const val ANDROIDX_TEST_JUNIT = "androidx.test.ext:junit-ktx:1.1.3" + const val ANDROIDX_TEST_RULES = "androidx.test:rules:$ANDROIDX_TEST_VERSION" + const val ANDROIDX_TEST_RUNNER = "androidx.test:runner:$ANDROIDX_TEST_VERSION" + + const val ROBOLECTRIC = "org.robolectric:robolectric:4.6.1" +} diff --git a/buildSrc/src/main/kotlin/Projects.kt b/buildSrc/src/main/kotlin/Projects.kt new file mode 100644 index 0000000..5af522d --- /dev/null +++ b/buildSrc/src/main/kotlin/Projects.kt @@ -0,0 +1,55 @@ +package mojito + +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.LibraryExtension +import com.android.build.gradle.internal.dsl.BaseAppModuleExtension +import org.gradle.api.JavaVersion +import org.gradle.api.Project +import org.gradle.api.plugins.ExtensionAware +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions + +fun Project.setupLibraryModule(block: LibraryExtension.() -> Unit = {}) { + setupBaseModule { + libraryVariants.all { + generateBuildConfigProvider?.configure { enabled = false } + } + testOptions { + unitTests.isIncludeAndroidResources = true + } + block() + } +} + +fun Project.setupAppModule(block: BaseAppModuleExtension.() -> Unit = {}) { + setupBaseModule { + defaultConfig { + versionCode = project.versionCode + versionName = project.versionName + vectorDrawables.useSupportLibrary = true + } + block() + } +} + +private inline fun Project.setupBaseModule(crossinline block: T.() -> Unit = {}) { + extensions.configure("android") { + compileSdkVersion(project.compileSdk) + defaultConfig { + minSdk = project.minSdk + targetSdk = project.targetSdk + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + (this as T).block() + } +} + +private fun BaseExtension.kotlinOptions(block: KotlinJvmOptions.() -> Unit) { + (this as ExtensionAware).extensions.configure("kotlinOptions", block) +} diff --git a/coilimageloader/build.gradle b/coilimageloader/build.gradle deleted file mode 100644 index b0a231b..0000000 --- a/coilimageloader/build.gradle +++ /dev/null @@ -1,43 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'com.github.dcendents.android-maven' -group = 'com.github.mikaelzero' -android { - def globalConfiguration = rootProject.extensions.getByName("ext") - compileSdkVersion globalConfiguration.androidCompileSdkVersion - - defaultConfig { - minSdkVersion globalConfiguration.androidMinSdkVersion - targetSdkVersion globalConfiguration.androidTargetSdkVersion - versionCode 1 - versionName "1.0" - consumerProguardFiles "consumer-rules.pro" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - buildToolsVersion '30.0.3' -} - -dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'com.squareup.okhttp3:okhttp:4.9.1' - implementation("io.coil-kt:coil-base:1.3.0") - implementation("io.coil-kt:coil-gif:1.3.0") - implementation("io.coil-kt:coil-svg:1.3.0") - implementation project(':mojito') -} diff --git a/coilimageloader/build.gradle.kts b/coilimageloader/build.gradle.kts new file mode 100644 index 0000000..003e8f3 --- /dev/null +++ b/coilimageloader/build.gradle.kts @@ -0,0 +1,25 @@ +import mojito.setupLibraryModule + +plugins { + id("com.android.library") + id("kotlin-android") + id("com.github.dcendents.android-maven") +} + +group = "com.github.mikaelzero" +setupLibraryModule { + defaultConfig { + minSdk = 16 + } +} + +dependencies { + implementation(mojito.Library.KOTLINX_STDLIB) + implementation(mojito.Library.ANDROIDX_APPCOMPAT) + implementation(mojito.Library.ANDROIDX_CORE) + implementation(mojito.Library.OKHTTP) + implementation("io.coil-kt:coil-base:1.3.0") + implementation("io.coil-kt:coil-gif:1.3.0") + implementation("io.coil-kt:coil-svg:1.3.0") + implementation(project(":mojito")) +} diff --git a/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/CoilImageLoader.kt b/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/CoilImageLoader.kt index 9244afb..c66ae5d 100644 --- a/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/CoilImageLoader.kt +++ b/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/CoilImageLoader.kt @@ -1,10 +1,10 @@ package net.mikaelzero.coilimageloader +import android.content.ContentResolver import android.content.Context import android.graphics.drawable.Drawable import android.net.Uri import android.os.Build.VERSION.SDK_INT -import androidx.core.net.toFile import coil.decode.GifDecoder import coil.decode.ImageDecoderDecoder import coil.decode.SvgDecoder @@ -16,8 +16,9 @@ import okhttp3.Cache import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.OkHttpClient import java.io.File -import java.util.ArrayList -import java.util.HashMap +import java.util.* +import kotlin.collections.set + /** * @Author: MikaelZero @@ -26,6 +27,12 @@ import java.util.HashMap */ class CoilImageLoader private constructor(val context: Context) : ImageLoader { + private val SCHEMES = setOf( + ContentResolver.SCHEME_FILE, + ContentResolver.SCHEME_ANDROID_RESOURCE, + ContentResolver.SCHEME_CONTENT + ) + private fun getImageLoader(context: Context): coil.ImageLoader { return coil.ImageLoader.Builder(context) .crossfade(true) @@ -69,7 +76,7 @@ class CoilImageLoader private constructor(val context: Context) : ImageLoader { val request = ImageRequest.Builder(context) .data(uri) .memoryCacheKey(uri.toString()) - .target(object : ImageDownloadTarget(context, uri?.toString().orEmpty()) { + .target(object : ImageDownloadTarget(uri?.toString().orEmpty()) { override fun onSuccess(result: Drawable) { super.onSuccess(result) val resource = uri.getCoilCacheFile() @@ -111,8 +118,8 @@ class CoilImageLoader private constructor(val context: Context) : ImageLoader { } fun Uri?.getCoilCacheFile(): File? { - if (this?.scheme == "file" || this?.scheme == "content") { - if (this.path == null) { + if (SCHEMES.contains(this?.scheme)) { + if (this?.path == null) { return null } return File(this.path!!) diff --git a/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/ImageDownloadTarget.kt b/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/ImageDownloadTarget.kt index 9806954..3e67ba1 100644 --- a/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/ImageDownloadTarget.kt +++ b/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/ImageDownloadTarget.kt @@ -1,22 +1,11 @@ package net.mikaelzero.coilimageloader -import android.content.Context import android.graphics.drawable.Drawable import net.mikaelzero.coilimageloader.ProgressSupport.expect import net.mikaelzero.coilimageloader.ProgressSupport.forget -import java.io.File -abstract class ImageDownloadTarget constructor( - private val context: Context, - private val mUrl: String, -) : coil.target.Target, ProgressSupport.ProgressListener { - private var sCounter = 0 - private val mTempFile: File - - init { - mTempFile = File(context.cacheDir, System.currentTimeMillis().toString() + "_" + nextCounter()) - } +abstract class ImageDownloadTarget constructor(private val mUrl: String) : coil.target.Target, ProgressSupport.ProgressListener { override fun onError(error: Drawable?) { super.onError(error) @@ -34,9 +23,4 @@ abstract class ImageDownloadTarget constructor( } - @Synchronized - fun nextCounter(): Int { - sCounter++ - return sCounter - } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index ce38300..5276a44 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,16 +1,12 @@ # Project-wide Gradle settings. - # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. - # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html - # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m - # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects @@ -20,35 +16,10 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official - -#enable R8 -android.enableR8=true -android.enableD8.desugaring=true - -#enables AGP to use gradle workers -android.enableGradleWorkers=true - -VERSION_NAME=1.0.0 - -POM_NAME=mojito -POM_GROUP_ID=com.github.mikaelzero.mojito -POM_URL=https://github.com/MikaelZero/mojito -POM_PACKAGING=aar -POM_DESCRIPTION=mojito - -POM_SCM_URL=https://github.com/MikaelZero/mojito -POM_SCM_CONNECTION=scm:git@https://github.com/MikaelZero/mojito.git -POM_SCM_DEV_CONNECTION=scm:git@https://github.com/MikaelZero/mojito.git - -POM_LICENCE_COMMENTS=A business-friendly OSS license -POM_LICENCE_NAME=The Apache Software License, Version 2.0 -POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt -POM_LICENCE_DIST=repo - -POM_DEVELOPER_ID=mikaelzero -POM_DEVELOPER_NAME=mikaelzero -POM_DEVELOPER_EMAIL=1604165677@qq.com -POM_DEVELOPER_URL=https://github.com/MikaelZero -POM_ISSUE_MANAGEMENT_SYSTEM=Github -POM_ISSUE_MANAGEMENT_URL=https://github.com/MikaelZero/mojito/issues -POM_INCEPTION_YEAR=2021 \ No newline at end of file +# Config +minSdk=16 +targetSdk=30 +compileSdk=30 +# Maven +GROUP=com.github.mikaelzero +VERSION_NAME=1.8.1 \ No newline at end of file diff --git a/mojito/build.gradle b/mojito/build.gradle deleted file mode 100644 index c679eb8..0000000 --- a/mojito/build.gradle +++ /dev/null @@ -1,48 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'com.github.dcendents.android-maven' -group = 'com.github.mikaelzero' -android { - def globalConfiguration = rootProject.extensions.getByName("ext") - compileSdkVersion globalConfiguration.androidCompileSdkVersion - - defaultConfig { - minSdkVersion globalConfiguration.androidMinSdkVersion - targetSdkVersion globalConfiguration.androidTargetSdkVersion - versionCode 1 - versionName "1" - - } - buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - buildToolsVersion '30.0.3' -} - -subprojects { - tasks.withType(Javadoc).all { enabled = false } -} - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.recyclerview:recyclerview:1.2.1' - implementation 'com.gyf.immersionbar:immersionbar:3.0.0' - implementation 'androidx.exifinterface:exifinterface:1.3.2' -} diff --git a/mojito/build.gradle.kts b/mojito/build.gradle.kts new file mode 100644 index 0000000..7983a88 --- /dev/null +++ b/mojito/build.gradle.kts @@ -0,0 +1,28 @@ +import mojito.setupLibraryModule + +plugins { + id("com.android.library") + id("kotlin-android") + id("kotlin-parcelize") + id("com.github.dcendents.android-maven") +} + +group = "com.github.mikaelzero" +setupLibraryModule { + defaultConfig { + minSdk = 16 + buildFeatures { + viewBinding = true + } + } +} + +dependencies { + implementation(mojito.Library.ANDROIDX_APPCOMPAT) + implementation(mojito.Library.ANDROIDX_CORE) + implementation(mojito.Library.ANDROIDX_RECYCLER_VIEW) + implementation(mojito.Library.KOTLINX_STDLIB) + implementation("com.gyf.immersionbar:immersionbar:3.0.0") + implementation("androidx.exifinterface:exifinterface:1.3.2") + implementation("androidx.viewpager2:viewpager2:1.0.0") +} diff --git a/mojito/src/main/java/net/mikaelzero/mojito/Mojito.kt b/mojito/src/main/java/net/mikaelzero/mojito/Mojito.kt index 61174b2..8ac784d 100644 --- a/mojito/src/main/java/net/mikaelzero/mojito/Mojito.kt +++ b/mojito/src/main/java/net/mikaelzero/mojito/Mojito.kt @@ -1,21 +1,21 @@ package net.mikaelzero.mojito +import android.app.Activity import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import net.mikaelzero.mojito.bean.ActivityConfig import net.mikaelzero.mojito.impl.DefaultMojitoConfig import net.mikaelzero.mojito.interfaces.IMojitoConfig import net.mikaelzero.mojito.interfaces.ImageViewLoadFactory import net.mikaelzero.mojito.loader.ImageLoader import net.mikaelzero.mojito.tools.DataWrapUtil +import net.mikaelzero.mojito.ui.ImageMojitoActivity class Mojito { companion object { - @JvmStatic - fun with(context: Context?): MojitoWrapper { - return MojitoWrapper(context) - } - @JvmStatic fun initialize( imageLoader: ImageLoader, @@ -64,5 +64,25 @@ class Mojito { DataWrapUtil.remove() imageLoader()?.cancelAll() } + + fun start(context: Context?, builder: MojitoBuilder.() -> Unit = {}) { + val configBean = MojitoBuilder().apply(builder).build() + ImageMojitoActivity.hasShowedAnimMap[configBean.position] = false + DataWrapUtil.put(configBean) + val activity = scanForActivity(context) + val intent = Intent(activity, ImageMojitoActivity::class.java) + activity?.startActivity(intent) + activity?.overridePendingTransition(0, 0) + } + + private fun scanForActivity(context: Context?): Activity? { + if (context == null) return null + if (context is Activity) { + return context + } else if (context is ContextWrapper) { + return scanForActivity(context.baseContext) + } + return null + } } } \ No newline at end of file diff --git a/mojito/src/main/java/net/mikaelzero/mojito/MojitoBuilder.kt b/mojito/src/main/java/net/mikaelzero/mojito/MojitoBuilder.kt new file mode 100644 index 0000000..be4a5cc --- /dev/null +++ b/mojito/src/main/java/net/mikaelzero/mojito/MojitoBuilder.kt @@ -0,0 +1,289 @@ +package net.mikaelzero.mojito + +import android.graphics.drawable.Drawable +import android.view.View +import android.widget.FrameLayout +import androidx.annotation.IdRes +import androidx.fragment.app.FragmentActivity +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager +import androidx.viewpager.widget.ViewPager +import net.mikaelzero.mojito.bean.ActivityConfig +import net.mikaelzero.mojito.bean.ViewParams +import net.mikaelzero.mojito.interfaces.* +import net.mikaelzero.mojito.loader.FragmentCoverLoader +import net.mikaelzero.mojito.loader.InstanceLoader +import net.mikaelzero.mojito.loader.MultiContentLoader +import net.mikaelzero.mojito.ui.ImageMojitoActivity + +/** + * @Author: MikaelZero + * @CreateDate: 2020/6/23 9:46 AM + * @Description: + */ +class MojitoBuilder { + private var originImageUrls: List? = null + private var targetImageUrls: List? = null + private var viewParams: List? = null + private var position: Int = 0 + private var headerSize: Int = 0 + private var footerSize: Int = 0 + private var autoLoadTarget: Boolean = true + + fun originImageUrls(data: List) = apply { + this.originImageUrls = data + } + + fun targetImageUrls(data: List) = apply { + this.targetImageUrls = data + } + + fun viewParams(data: List) = apply { + this.viewParams = data + } + + fun position(data: Int) = apply { + this.position = data + } + + fun headerSize(data: Int) = apply { + this.headerSize = data + } + + fun footerSize(data: Int) = apply { + this.footerSize = data + } + + fun autoLoadTarget(data: Boolean) = apply { + this.autoLoadTarget = data + } + + fun urls(imageUrl: String) = apply { + this.originImageUrls = listOf(imageUrl) + } + + fun urls(imageUrl: String, targetUrl: String) = apply { + this.originImageUrls = listOf(imageUrl) + this.targetImageUrls = listOf(targetUrl) + } + + + fun urls(imageUrls: List?) = apply { + this.originImageUrls = imageUrls + } + + fun urls(imageUrls: List?, targetImageUrls: List?) = apply { + this.originImageUrls = imageUrls + this.targetImageUrls = targetImageUrls + } + + fun position(position: Int, headerSize: Int = 0, footerSize: Int = 0) = apply { + this.headerSize = headerSize + this.footerSize = footerSize + this.position = position + } + + fun views(view: View?) = apply { + val views = arrayOfNulls(1) + views[0] = view + views(views) + } + + fun views(views: Array) = apply { + val list = mutableListOf() + for (imageView in views) { + val imageBean = ViewParams() + if (imageView == null) { + imageBean.left = 0 + imageBean.top = 0 + imageBean.width = 0 + imageBean.height = 0 + } else { + val location = IntArray(2) + imageView.getLocationOnScreen(location) + imageBean.left = location[0] + imageBean.top = location[1] + imageBean.width = imageView.width + imageBean.height = imageView.height + } + list.add(imageBean) + } + this.viewParams = list + } + + fun views(recyclerView: RecyclerView, @IdRes viewId: Int) = apply { + val originImageViewList = mutableListOf() + val childCount = recyclerView.childCount + for (i in 0 until childCount) { + val originImage = recyclerView.getChildAt(i).findViewById(viewId) + if (originImage != null) { + originImageViewList.add(originImage) + } + } + val layoutManager = recyclerView.layoutManager + var firstPos = 0 + var lastPos = 0 + val totalCount = layoutManager!!.itemCount - this.headerSize - this.footerSize + when (layoutManager) { + is GridLayoutManager -> { + firstPos = layoutManager.findFirstVisibleItemPosition() + lastPos = layoutManager.findLastVisibleItemPosition() + + } + is LinearLayoutManager -> { + firstPos = layoutManager.findFirstVisibleItemPosition() + lastPos = layoutManager.findLastVisibleItemPosition() + } + is StaggeredGridLayoutManager -> { + val lastVisibleItemPositions = layoutManager.findLastVisibleItemPositions(null) + val firstVisibleItemPositions = layoutManager.findFirstVisibleItemPositions(null) + lastPos = getLastVisibleItem(lastVisibleItemPositions) + firstPos = getFirstVisibleItem(firstVisibleItemPositions) + } + } + firstPos = if (firstPos < this.headerSize) 0 else firstPos - this.headerSize + lastPos = if (lastPos > totalCount) totalCount - 1 else lastPos - this.headerSize + fillPlaceHolder(originImageViewList, totalCount, firstPos, lastPos) + val views = arrayOfNulls(originImageViewList.size) + for (i in originImageViewList.indices) { + views[i] = originImageViewList[i] + } + views(views) + } + + /** + * @return Last visible item position for staggeredGridLayoutManager + */ + private fun getLastVisibleItem(lastVisibleItemPositions: IntArray): Int { + var maxSize = 0 + for (position in lastVisibleItemPositions) { + if (position > maxSize) { + maxSize = position + } + } + return maxSize + } + + /** + * @return First visible item position for staggeredGridLayoutManager + */ + private fun getFirstVisibleItem(firstVisibleItemPositions: IntArray): Int { + var minSize = 0 + if (firstVisibleItemPositions.isNotEmpty()) { + minSize = firstVisibleItemPositions[0] + for (position in firstVisibleItemPositions) { + if (position < minSize) { + minSize = position + } + } + } + return minSize + } + + /** + * fill recycleView + */ + private fun fillPlaceHolder(originImageList: MutableList, totalCount: Int, firstPos: Int, lastPos: Int) { + if (firstPos > 0) { + for (pos in firstPos downTo 1) { + originImageList.add(0, null) + } + } + if (lastPos < totalCount) { + for (i in totalCount - 1 - lastPos downTo 1) { + originImageList.add(null) + } + } + } + + + inline fun mojitoListener( + crossinline onStartAnim: (position: Int) -> Unit = {}, + crossinline onClick: (view: View, x: Float, y: Float, position: Int) -> Unit = { _, _, _, _ -> }, + crossinline onLongClick: (fragmentActivity: FragmentActivity?, view: View, x: Float, y: Float, position: Int) -> Unit = { _, _, _, _, _ -> }, + crossinline onShowFinish: (mojitoView: MojitoView, showImmediately: Boolean) -> Unit = { _, _ -> }, + crossinline onMojitoViewFinish: (pagePosition: Int) -> Unit = {}, + crossinline onDrag: (view: MojitoView, moveX: Float, moveY: Float) -> Unit = { _, _, _ -> }, + crossinline onLongImageMove: (ratio: Float) -> Unit = {}, + crossinline onViewPageSelected: (position: Int) -> Unit = {}, + ) = setOnMojitoListener(object : OnMojitoListener { + override fun onStartAnim(position: Int) = onStartAnim(position) + + override fun onClick(view: View, x: Float, y: Float, position: Int) = onClick(view, x, y, position) + + override fun onLongClick(fragmentActivity: FragmentActivity?, view: View, x: Float, y: Float, position: Int) = onLongClick(fragmentActivity, view, x, y, position) + + override fun onShowFinish(mojitoView: MojitoView, showImmediately: Boolean) = onShowFinish(mojitoView, showImmediately) + + override fun onMojitoViewFinish(pagePosition: Int) = onMojitoViewFinish(pagePosition) + + override fun onDrag(view: MojitoView, moveX: Float, moveY: Float) = onDrag(view, moveX, moveY) + + override fun onLongImageMove(ratio: Float) = onLongImageMove(ratio) + + override fun onViewPageSelected(position: Int) = onViewPageSelected(position) + + }) + + fun setOnMojitoListener(target: OnMojitoListener?) = apply { + ImageMojitoActivity.onMojitoListener = target + } + + inline fun progressLoader( + crossinline providerInstance: () -> IProgress + ) = setProgressLoader(object : InstanceLoader { + override fun providerInstance(): IProgress = providerInstance() + }) + + + fun setProgressLoader(loader: InstanceLoader) = apply { + ImageMojitoActivity.progressLoader = loader + } + + inline fun fragmentCoverLoader( + crossinline providerInstance: () -> FragmentCoverLoader + ) = setFragmentCoverLoader(object : InstanceLoader { + override fun providerInstance(): FragmentCoverLoader = providerInstance() + }) + + fun setFragmentCoverLoader(loader: InstanceLoader) = apply { + ImageMojitoActivity.fragmentCoverLoader = loader + } + + inline fun multiContentLoader( + crossinline providerLoader: (position: Int) -> ImageViewLoadFactory, + crossinline providerEnableTargetLoad: (position: Int) -> Boolean, + ) = setMultiContentLoader(object : MultiContentLoader { + override fun providerLoader(position: Int): ImageViewLoadFactory = providerLoader(position) + + override fun providerEnableTargetLoad(position: Int): Boolean = providerEnableTargetLoad(position) + }) + + fun setMultiContentLoader(loader: MultiContentLoader) = apply { + ImageMojitoActivity.multiContentLoader = loader + + } + + fun setActivityCoverLoader(on: ActivityCoverLoader) = apply { + ImageMojitoActivity.activityCoverLoader = on + + } + + fun setIndicator(on: IIndicator?) = apply { + ImageMojitoActivity.iIndicator = on + } + + fun build(): ActivityConfig { + return ActivityConfig( + originImageUrls = this.originImageUrls, + targetImageUrls = this.targetImageUrls, + viewParams = this.viewParams, + position = this.position, + headerSize = this.headerSize, + footerSize = this.footerSize, + autoLoadTarget = this.autoLoadTarget + ) + } +} \ No newline at end of file diff --git a/mojito/src/main/java/net/mikaelzero/mojito/MojitoWrapper.kt b/mojito/src/main/java/net/mikaelzero/mojito/MojitoWrapper.kt deleted file mode 100644 index 1628066..0000000 --- a/mojito/src/main/java/net/mikaelzero/mojito/MojitoWrapper.kt +++ /dev/null @@ -1,243 +0,0 @@ -package net.mikaelzero.mojito - -import android.app.Activity -import android.content.Context -import android.content.ContextWrapper -import android.content.Intent -import android.view.View -import androidx.annotation.IdRes -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.StaggeredGridLayoutManager -import net.mikaelzero.mojito.bean.ActivityConfig -import net.mikaelzero.mojito.bean.ViewParams -import net.mikaelzero.mojito.interfaces.ActivityCoverLoader -import net.mikaelzero.mojito.interfaces.IIndicator -import net.mikaelzero.mojito.interfaces.IProgress -import net.mikaelzero.mojito.interfaces.OnMojitoListener -import net.mikaelzero.mojito.loader.FragmentCoverLoader -import net.mikaelzero.mojito.loader.InstanceLoader -import net.mikaelzero.mojito.loader.MultiContentLoader -import net.mikaelzero.mojito.tools.DataWrapUtil -import net.mikaelzero.mojito.ui.ImageMojitoActivity - -/** - * @Author: MikaelZero - * @CreateDate: 2020/6/23 9:46 AM - * @Description: - */ -class MojitoWrapper constructor(val context: Context?) { - private val configBean = ActivityConfig() - fun urls(imageUrl: String): MojitoWrapper { - configBean.originImageUrls = listOf(imageUrl) - return this - } - - fun urls(imageUrl: String, targetUrl: String): MojitoWrapper { - configBean.originImageUrls = listOf(imageUrl) - configBean.targetImageUrls = listOf(targetUrl) - return this - } - - - fun urls(imageUrls: List?): MojitoWrapper { - configBean.originImageUrls = imageUrls - return this - } - - fun urls(imageUrls: List?, targetImageUrls: List?): MojitoWrapper { - configBean.originImageUrls = imageUrls - configBean.targetImageUrls = targetImageUrls - return this - } - - fun position(position: Int, headerSize: Int = 0, footerSize: Int = 0): MojitoWrapper { - configBean.headerSize = headerSize - configBean.footerSize = footerSize - configBean.position = position - return this - } - - fun views(view: View?): MojitoWrapper { - val views = arrayOfNulls(1) - views[0] = view - return views(views) - } - - fun views(recyclerView: RecyclerView, @IdRes viewId: Int): MojitoWrapper { - val originImageViewList = mutableListOf() - val childCount = recyclerView.childCount - for (i in 0 until childCount) { - val originImage = recyclerView.getChildAt(i).findViewById(viewId) - if (originImage != null) { - originImageViewList.add(originImage) - } - } - val layoutManager = recyclerView.layoutManager - var firstPos = 0 - var lastPos = 0 - val totalCount = layoutManager!!.itemCount - configBean.headerSize - configBean.footerSize - when (layoutManager) { - is GridLayoutManager -> { - firstPos = layoutManager.findFirstVisibleItemPosition() - lastPos = layoutManager.findLastVisibleItemPosition() - - } - is LinearLayoutManager -> { - firstPos = layoutManager.findFirstVisibleItemPosition() - lastPos = layoutManager.findLastVisibleItemPosition() - } - is StaggeredGridLayoutManager -> { - val lastVisibleItemPositions = layoutManager.findLastVisibleItemPositions(null) - val firstVisibleItemPositions = layoutManager.findFirstVisibleItemPositions(null) - lastPos = getLastVisibleItem(lastVisibleItemPositions) - firstPos = getFirstVisibleItem(firstVisibleItemPositions) - } - } - firstPos = if (firstPos < configBean.headerSize) 0 else firstPos - configBean.headerSize - lastPos = if (lastPos > totalCount) totalCount - 1 else lastPos - configBean.headerSize - fillPlaceHolder(originImageViewList, totalCount, firstPos, lastPos) - val views = arrayOfNulls(originImageViewList.size) - for (i in originImageViewList.indices) { - views[i] = originImageViewList[i] - } - return views(views) - } - - /** - * @return Last visible item position for staggeredGridLayoutManager - */ - private fun getLastVisibleItem(lastVisibleItemPositions: IntArray): Int { - var maxSize = 0 - for (position in lastVisibleItemPositions) { - if (position > maxSize) { - maxSize = position - } - } - return maxSize - } - - /** - * @return First visible item position for staggeredGridLayoutManager - */ - private fun getFirstVisibleItem(firstVisibleItemPositions: IntArray): Int { - var minSize = 0 - if (firstVisibleItemPositions.isNotEmpty()) { - minSize = firstVisibleItemPositions[0] - for (position in firstVisibleItemPositions) { - if (position < minSize) { - minSize = position - } - } - } - return minSize - } - - /** - * fill recycleView - */ - private fun fillPlaceHolder(originImageList: MutableList, totalCount: Int, firstPos: Int, lastPos: Int) { - if (firstPos > 0) { - for (pos in firstPos downTo 1) { - originImageList.add(0, null) - } - } - if (lastPos < totalCount) { - for (i in totalCount - 1 - lastPos downTo 1) { - originImageList.add(null) - } - } - } - - - fun views(views: Array): MojitoWrapper { - val list = mutableListOf() - for (imageView in views) { - val imageBean = ViewParams() - if (imageView == null) { - imageBean.left = 0 - imageBean.top = 0 - imageBean.width = 0 - imageBean.height = 0 - } else { - val location = IntArray(2) - imageView.getLocationOnScreen(location) - imageBean.left = location[0] - imageBean.top = location[1] - imageBean.width = imageView.width - imageBean.height = imageView.height - } - list.add(imageBean) - } - configBean.viewParams = list - return this - } - - fun autoLoadTarget(autoLoadTarget: Boolean): MojitoWrapper { - configBean.autoLoadTarget = autoLoadTarget - return this - } - - /** - * Listener start - */ - fun setOnMojitoListener(onMojitoListener: OnMojitoListener): MojitoWrapper { - ImageMojitoActivity.onMojitoListener = onMojitoListener - return this - } - - - fun setProgressLoader(loader: InstanceLoader): MojitoWrapper { - ImageMojitoActivity.progressLoader = loader - return this - } - - fun setFragmentCoverLoader(loader: InstanceLoader): MojitoWrapper { - ImageMojitoActivity.fragmentCoverLoader = loader - return this - } - - fun setMultiContentLoader(loader: MultiContentLoader): MojitoWrapper { - ImageMojitoActivity.multiContentLoader = loader - return this - } - - fun setActivityCoverLoader(on: ActivityCoverLoader): MojitoWrapper { - ImageMojitoActivity.activityCoverLoader = on - return this - } - - fun setIndicator(on: IIndicator?): MojitoWrapper { - ImageMojitoActivity.iIndicator = on - return this - } - - /** - * Listener end - */ - - - fun start() { - assert() - ImageMojitoActivity.hasShowedAnimMap[configBean.position] = false - DataWrapUtil.put(configBean) - val activity = scanForActivity(context) - val intent = Intent(activity, ImageMojitoActivity::class.java) - activity?.startActivity(intent) - activity?.overridePendingTransition(0, 0) - } - - private fun assert() { - } - - private fun scanForActivity(context: Context?): Activity? { - if (context == null) return null - if (context is Activity) { - return context - } else if (context is ContextWrapper) { - return scanForActivity(context.baseContext) - } - return null - } -} \ No newline at end of file diff --git a/mojito/src/main/java/net/mikaelzero/mojito/bean/ActivityConfig.kt b/mojito/src/main/java/net/mikaelzero/mojito/bean/ActivityConfig.kt index 5fb4d59..d1e9438 100644 --- a/mojito/src/main/java/net/mikaelzero/mojito/bean/ActivityConfig.kt +++ b/mojito/src/main/java/net/mikaelzero/mojito/bean/ActivityConfig.kt @@ -1,7 +1,7 @@ package net.mikaelzero.mojito.bean import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize @Parcelize data class ActivityConfig( diff --git a/mojito/src/main/java/net/mikaelzero/mojito/bean/FragmentConfig.kt b/mojito/src/main/java/net/mikaelzero/mojito/bean/FragmentConfig.kt index a0814c8..af47f79 100644 --- a/mojito/src/main/java/net/mikaelzero/mojito/bean/FragmentConfig.kt +++ b/mojito/src/main/java/net/mikaelzero/mojito/bean/FragmentConfig.kt @@ -1,7 +1,7 @@ package net.mikaelzero.mojito.bean import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize /** * @Author: MikaelZero diff --git a/mojito/src/main/java/net/mikaelzero/mojito/ext/MojitoViewExt.kt b/mojito/src/main/java/net/mikaelzero/mojito/ext/MojitoViewExt.kt new file mode 100644 index 0000000..ad81571 --- /dev/null +++ b/mojito/src/main/java/net/mikaelzero/mojito/ext/MojitoViewExt.kt @@ -0,0 +1,34 @@ +package net.mikaelzero.mojito.ext + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import net.mikaelzero.mojito.Mojito +import net.mikaelzero.mojito.MojitoBuilder + +/** + * @Author: MikaelZero + * @CreateDate: 2021/7/30 9:45 上午 + * @Description: + */ + +fun RecyclerView.mojito(itemId: Int, builder: MojitoBuilder.() -> Unit = {}) { + Mojito.start(this.context) { + apply( + builder.apply { + views(this@mojito, itemId) + } + ) + } +} + +fun View.mojito(url: String, builder: MojitoBuilder.() -> Unit = {}) { + Mojito.start(this.context) { + apply( + builder.apply { + urls(url) + views(this@mojito) + } + ) + + } +} \ No newline at end of file diff --git a/mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndexIndicator.java b/mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndexIndicator.java deleted file mode 100644 index 0c9519a..0000000 --- a/mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndexIndicator.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.mikaelzero.mojito.impl; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.view.Gravity; -import android.view.View; -import android.widget.FrameLayout; - -import androidx.viewpager.widget.ViewPager; - -import net.mikaelzero.mojito.interfaces.IIndicator; -import net.mikaelzero.mojito.tools.Utils; - -/** - * @Author: MikaelZero - * @CreateDate: 2020/6/13 5:39 PM - * @Description: - */ -public class CircleIndexIndicator implements IIndicator { - - private CircleIndicator circleIndicator; - private int originBottomMargin = 10; - private int currentBottomMargin = originBottomMargin; - - @Override - public void attach(FrameLayout parent) { - originBottomMargin = Utils.dip2px(parent.getContext(), 16); - FrameLayout.LayoutParams indexLp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, Utils.dip2px(parent.getContext(), 36)); - indexLp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - indexLp.bottomMargin = originBottomMargin; - - circleIndicator = new CircleIndicator(parent.getContext()); - circleIndicator.setGravity(Gravity.CENTER_VERTICAL); - circleIndicator.setLayoutParams(indexLp); - - parent.addView(circleIndicator); - } - - @Override - public void onShow(ViewPager viewPager) { - circleIndicator.setVisibility(View.VISIBLE); - circleIndicator.setViewPager(viewPager); - } - - - @Override - public void move(float moveX, float moveY) { - if (circleIndicator == null) { - return; - } - FrameLayout.LayoutParams indexLp = (FrameLayout.LayoutParams) circleIndicator.getLayoutParams(); - currentBottomMargin = Math.round(originBottomMargin - moveY / 6f); - if (currentBottomMargin > originBottomMargin) { - currentBottomMargin = originBottomMargin; - } - indexLp.bottomMargin = currentBottomMargin; - circleIndicator.setLayoutParams(indexLp); - } - - @Override - public void fingerRelease(boolean isToMax, boolean isToMin) { - if (circleIndicator == null) { - return; - } - int begin = 0; - int end = 0; - if (isToMax) { - begin = currentBottomMargin; - end = originBottomMargin; - } - if (isToMin) { - circleIndicator.setVisibility(View.GONE); - return; - } - final FrameLayout.LayoutParams indexLp = (FrameLayout.LayoutParams) circleIndicator.getLayoutParams(); - ValueAnimator valueAnimator = ValueAnimator.ofInt(begin, end); - valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - indexLp.bottomMargin = (int) animation.getAnimatedValue(); - circleIndicator.setLayoutParams(indexLp); - } - }); - valueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - - } - }); - valueAnimator.setDuration(300).start(); - } -} diff --git a/mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndicator.java b/mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndicator.java deleted file mode 100644 index 15bd82b..0000000 --- a/mojito/src/main/java/net/mikaelzero/mojito/impl/CircleIndicator.java +++ /dev/null @@ -1,274 +0,0 @@ -package net.mikaelzero.mojito.impl; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.TypedArray; -import android.database.DataSetObserver; -import android.graphics.Color; -import android.graphics.drawable.GradientDrawable; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.View; -import android.view.animation.Interpolator; -import android.widget.LinearLayout; - -import androidx.viewpager.widget.ViewPager; - -import net.mikaelzero.mojito.R; - - -public class CircleIndicator extends LinearLayout { - - private final static int DEFAULT_INDICATOR_WIDTH = 5; - - private ViewPager mViewpager; - private GradientDrawable mIndicatorBackground; - - private Animator mAnimatorOut; - private Animator mAnimatorIn; - private Animator mImmediateAnimatorOut; - private Animator mImmediateAnimatorIn; - - private int mIndicatorMargin = -1; - private int mIndicatorWidth = -1; - private int mIndicatorHeight = -1; - - private int mLastPosition = -1; - private final ViewPager.OnPageChangeListener mInternalPageChangeListener = new ViewPager.OnPageChangeListener() { - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageSelected(int position) { - - if (mViewpager.getAdapter() == null || mViewpager.getAdapter().getCount() <= 0) { - return; - } - - if (mAnimatorIn.isRunning()) { - mAnimatorIn.end(); - mAnimatorIn.cancel(); - } - - if (mAnimatorOut.isRunning()) { - mAnimatorOut.end(); - mAnimatorOut.cancel(); - } - - View currentIndicator; - if (mLastPosition >= 0 && (currentIndicator = getChildAt(mLastPosition)) != null) { - currentIndicator.setBackgroundDrawable(mIndicatorBackground); - mAnimatorIn.setTarget(currentIndicator); - mAnimatorIn.start(); - } - - View selectedIndicator = getChildAt(position); - if (selectedIndicator != null) { - selectedIndicator.setBackgroundDrawable(mIndicatorBackground); - mAnimatorOut.setTarget(selectedIndicator); - mAnimatorOut.start(); - } - mLastPosition = position; - } - - @Override - public void onPageScrollStateChanged(int state) { - } - }; - - private DataSetObserver mInternalDataSetObserver = new DataSetObserver() { - @Override - public void onChanged() { - super.onChanged(); - if (mViewpager == null) { - return; - } - - int newCount = mViewpager.getAdapter().getCount(); - int currentCount = getChildCount(); - - if (newCount == currentCount) { // No change - return; - } else if (mLastPosition < newCount) { - mLastPosition = mViewpager.getCurrentItem(); - } else { - mLastPosition = -1; - } - - createIndicators(); - } - }; - - public CircleIndicator(Context context) { - this(context, null); - } - - public CircleIndicator(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs); - } - - private void init(Context context, AttributeSet attrs) { - mIndicatorBackground = new GradientDrawable(); - mIndicatorBackground.setShape(GradientDrawable.OVAL); - mIndicatorBackground.setColor(Color.WHITE); - - handleTypedArray(context, attrs); - checkIndicatorConfig(context); - } - - private void handleTypedArray(Context context, AttributeSet attrs) { - if (attrs == null) { - return; - } - - TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleIndicator); - mIndicatorWidth = - typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_width, -1); - mIndicatorHeight = - typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_height, -1); - mIndicatorMargin = - typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_margin, -1); - - int orientation = typedArray.getInt(R.styleable.CircleIndicator_ci_orientation, -1); - setOrientation(orientation == VERTICAL ? VERTICAL : HORIZONTAL); - - int gravity = typedArray.getInt(R.styleable.CircleIndicator_ci_gravity, -1); - setGravity(gravity >= 0 ? gravity : Gravity.CENTER); - - typedArray.recycle(); - } - - /** - * Create and configure Indicator in Java code. - */ - public void configureIndicator(int indicatorWidth, int indicatorHeight, int indicatorMargin) { - mIndicatorWidth = indicatorWidth; - mIndicatorHeight = indicatorHeight; - mIndicatorMargin = indicatorMargin; - - checkIndicatorConfig(getContext()); - } - - private void checkIndicatorConfig(Context context) { - mIndicatorWidth = (mIndicatorWidth < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorWidth; - mIndicatorHeight = - (mIndicatorHeight < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorHeight; - mIndicatorMargin = - (mIndicatorMargin < 0) ? dip2px(DEFAULT_INDICATOR_WIDTH) : mIndicatorMargin; - - mAnimatorOut = createAnimatorOut(); - mImmediateAnimatorOut = createAnimatorOut(); - mImmediateAnimatorOut.setDuration(0); - - mAnimatorIn = createAnimatorIn(context); - mImmediateAnimatorIn = createAnimatorIn(context); - mImmediateAnimatorIn.setDuration(0); - } - - private Animator createAnimatorOut() { - ObjectAnimator alphaAnima = ObjectAnimator.ofFloat(null, "alpha", .5f, 1.f); - ObjectAnimator scaleX = ObjectAnimator.ofFloat(null, "scaleX", 1.0f, 1.8f); - ObjectAnimator scaleY = ObjectAnimator.ofFloat(null, "scaleY", 1.0f, 1.8f); - - AnimatorSet animatorOut = new AnimatorSet(); - animatorOut.play(alphaAnima).with(scaleX).with(scaleY); - return animatorOut; - } - - private Animator createAnimatorIn(Context context) { - Animator animatorIn = createAnimatorOut(); - animatorIn.setInterpolator(new ReverseInterpolator()); - return animatorIn; - } - - public void setViewPager(ViewPager viewPager) { - mViewpager = viewPager; - if (mViewpager != null && mViewpager.getAdapter() != null) { - mLastPosition = -1; - createIndicators(); - mViewpager.removeOnPageChangeListener(mInternalPageChangeListener); - mViewpager.addOnPageChangeListener(mInternalPageChangeListener); - mInternalPageChangeListener.onPageSelected(mViewpager.getCurrentItem()); - } - } - - public DataSetObserver getDataSetObserver() { - return mInternalDataSetObserver; - } - - /** - * @deprecated User ViewPager addOnPageChangeListener - */ - @Deprecated - public void setOnPageChangeListener(ViewPager.OnPageChangeListener onPageChangeListener) { - if (mViewpager == null) { - throw new NullPointerException("can not find Viewpager , setViewPager first"); - } - mViewpager.removeOnPageChangeListener(onPageChangeListener); - mViewpager.addOnPageChangeListener(onPageChangeListener); - } - - private void createIndicators() { - removeAllViews(); - int count = mViewpager.getAdapter().getCount(); - if (count <= 0) { - return; - } - int currentItem = mViewpager.getCurrentItem(); - int orientation = getOrientation(); - - for (int i = 0; i < count; i++) { - if (currentItem == i) { - addIndicator(orientation, mImmediateAnimatorOut); - } else { - addIndicator(orientation, mImmediateAnimatorIn); - } - } - } - - private void addIndicator(int orientation, Animator animator) { - if (animator.isRunning()) { - animator.end(); - animator.cancel(); - } - - View indicator = new View(getContext()); - indicator.setBackgroundDrawable(mIndicatorBackground); - addView(indicator, mIndicatorWidth, mIndicatorHeight); - LayoutParams lp = (LayoutParams) indicator.getLayoutParams(); - - if (orientation == HORIZONTAL) { - lp.leftMargin = mIndicatorMargin; - lp.rightMargin = mIndicatorMargin; - } else { - lp.topMargin = mIndicatorMargin; - lp.bottomMargin = mIndicatorMargin; - } - - indicator.setLayoutParams(lp); - - animator.setTarget(indicator); - animator.start(); - } - - public int dip2px(float dpValue) { - final float scale = getResources().getDisplayMetrics().density; - return (int) (dpValue * scale + 0.5f); - } - - private class ReverseInterpolator implements Interpolator { - @Override - public float getInterpolation(float value) { - return Math.abs(1.0f - value); - } - } -} \ No newline at end of file diff --git a/mojito/src/main/java/net/mikaelzero/mojito/impl/NumIndicator.java b/mojito/src/main/java/net/mikaelzero/mojito/impl/NumIndicator.java index 5107dbd..05a7343 100644 --- a/mojito/src/main/java/net/mikaelzero/mojito/impl/NumIndicator.java +++ b/mojito/src/main/java/net/mikaelzero/mojito/impl/NumIndicator.java @@ -10,6 +10,7 @@ import android.widget.TextView; import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.widget.ViewPager2; import net.mikaelzero.mojito.interfaces.IIndicator; import net.mikaelzero.mojito.tools.Utils; @@ -44,10 +45,10 @@ public void attach(FrameLayout parent) { } @Override - public void onShow(ViewPager viewPager) { + public void onShow(ViewPager2 viewPager) { numTv.setVisibility(View.VISIBLE); if (viewPager.getAdapter() != null) { - viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { @@ -55,16 +56,15 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse @Override public void onPageSelected(int position) { - String str = (position + 1) + "/" + viewPager.getAdapter().getCount(); + String str = (position + 1) + "/" + viewPager.getAdapter().getItemCount(); numTv.setText(str); } @Override public void onPageScrollStateChanged(int state) { - } }); - String firstStr = (viewPager.getCurrentItem() + 1) + "/" + viewPager.getAdapter().getCount(); + String firstStr = (viewPager.getCurrentItem() + 1) + "/" + viewPager.getAdapter().getItemCount(); numTv.setText(firstStr); } } diff --git a/mojito/src/main/java/net/mikaelzero/mojito/interfaces/IIndicator.java b/mojito/src/main/java/net/mikaelzero/mojito/interfaces/IIndicator.java index a0e5bf4..22637ae 100644 --- a/mojito/src/main/java/net/mikaelzero/mojito/interfaces/IIndicator.java +++ b/mojito/src/main/java/net/mikaelzero/mojito/interfaces/IIndicator.java @@ -3,12 +3,13 @@ import android.widget.FrameLayout; import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.widget.ViewPager2; public interface IIndicator { void attach(FrameLayout parent); - void onShow(ViewPager viewPager); + void onShow(ViewPager2 viewPager); /** * 拖动的时候 移动的 X 和 Y 距离 diff --git a/mojito/src/main/java/net/mikaelzero/mojito/tools/NoScrollViewPager.java b/mojito/src/main/java/net/mikaelzero/mojito/tools/NoScrollViewPager.java deleted file mode 100644 index 23bb35b..0000000 --- a/mojito/src/main/java/net/mikaelzero/mojito/tools/NoScrollViewPager.java +++ /dev/null @@ -1,60 +0,0 @@ -package net.mikaelzero.mojito.tools; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; - -import androidx.viewpager.widget.ViewPager; - -/** - * @Author: MikaelZero - * @CreateDate: 2020/6/13 11:56 AM - * @Description: - */ -public class NoScrollViewPager extends ViewPager { - private boolean isLocked; - - public NoScrollViewPager(Context context) { - super(context); - } - - public NoScrollViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - public void setCurrentItem(int item, boolean smoothScroll) { - super.setCurrentItem(item, smoothScroll); - } - - @Override - public void setCurrentItem(int item) { - super.setCurrentItem(item, false); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (!isLocked) { - try { - return super.onInterceptTouchEvent(ev); - } catch (IllegalArgumentException ex) { - ex.printStackTrace(); - return false; - } - } - return false; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - return !isLocked && super.onTouchEvent(event); - } - - public void setLocked(boolean isLocked) { - this.isLocked = isLocked; - } - - public boolean isLocked() { - return isLocked; - } -} diff --git a/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoActivity.kt b/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoActivity.kt index 9bb1300..93d88eb 100644 --- a/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoActivity.kt +++ b/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoActivity.kt @@ -1,50 +1,60 @@ package net.mikaelzero.mojito.ui import android.content.Context +import android.os.Build import android.os.Bundle import android.view.KeyEvent import android.view.Window +import android.view.WindowInsets import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentPagerAdapter -import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 import com.gyf.immersionbar.ImmersionBar -import kotlinx.android.synthetic.main.activity_image.* import net.mikaelzero.mojito.Mojito -import net.mikaelzero.mojito.R import net.mikaelzero.mojito.bean.ActivityConfig import net.mikaelzero.mojito.bean.FragmentConfig -import net.mikaelzero.mojito.bean.ViewParams import net.mikaelzero.mojito.bean.ViewPagerBean +import net.mikaelzero.mojito.bean.ViewParams +import net.mikaelzero.mojito.databinding.ActivityImageBinding import net.mikaelzero.mojito.interfaces.* import net.mikaelzero.mojito.loader.FragmentCoverLoader import net.mikaelzero.mojito.loader.InstanceLoader import net.mikaelzero.mojito.loader.MultiContentLoader import net.mikaelzero.mojito.tools.DataWrapUtil -import net.mikaelzero.mojito.tools.MojitoConstant class ImageMojitoActivity : AppCompatActivity(), IMojitoActivity { + private lateinit var binding: ActivityImageBinding private var viewParams: List? = null lateinit var activityConfig: ActivityConfig - private lateinit var imageViewPagerAdapter: FragmentPagerAdapter + private lateinit var imageViewPagerAdapter: FragmentStateAdapter val fragmentMap = hashMapOf() override fun onCreate(savedInstanceState: Bundle?) { requestWindowFeature(Window.FEATURE_NO_TITLE) super.onCreate(savedInstanceState) - window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + @Suppress("DEPRECATION") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + window.insetsController?.hide(WindowInsets.Type.statusBars()) + } else { + window.setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN + ) + } if (Mojito.mojitoConfig().transparentNavigationBar()) { ImmersionBar.with(this).transparentBar().init() } else { ImmersionBar.with(this).transparentStatusBar().init() } - setContentView(R.layout.activity_image) + binding = ActivityImageBinding.inflate(layoutInflater) + setContentView(binding.root) - userCustomLayout.removeAllViews() + binding.userCustomLayout.removeAllViews() activityCoverLoader?.let { activityCoverLoader?.attach(this) - userCustomLayout.addView(activityCoverLoader!!.providerView()) + binding.userCustomLayout.addView(activityCoverLoader!!.providerView()) } if (DataWrapUtil.config == null) { @@ -88,8 +98,10 @@ class ImageMojitoActivity : AppCompatActivity(), IMojitoActivity { ) ) } - imageViewPagerAdapter = object : FragmentPagerAdapter(supportFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - override fun getItem(position: Int): Fragment { + imageViewPagerAdapter = object : FragmentStateAdapter(supportFragmentManager, lifecycle) { + override fun getItemCount(): Int = viewPagerBeans.size + + override fun createFragment(position: Int): Fragment { val fragment = fragmentMap[position] return if (fragment == null) { val fragmentConfig = FragmentConfig( @@ -107,16 +119,11 @@ class ImageMojitoActivity : AppCompatActivity(), IMojitoActivity { fragment } } - - override fun getCount(): Int = viewPagerBeans.size } - viewPager.adapter = imageViewPagerAdapter - viewPager.setCurrentItem(currentPosition, false) - activityCoverLoader?.pageChange( - imageViewPagerAdapter.getItem(viewPager.currentItem) as IMojitoFragment, - viewPagerBeans.size, currentPosition - ) - viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + binding.viewPager.adapter = imageViewPagerAdapter + binding.viewPager.setCurrentItem(currentPosition, false) + activityCoverLoader?.pageChange(getCurrentFragment(), viewPagerBeans.size, currentPosition) + binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageScrollStateChanged(state: Int) { } @@ -126,22 +133,19 @@ class ImageMojitoActivity : AppCompatActivity(), IMojitoActivity { } override fun onPageSelected(position: Int) { - activityCoverLoader?.pageChange( - imageViewPagerAdapter.getItem(viewPager.currentItem) as IMojitoFragment, - viewPagerBeans.size, position - ) + activityCoverLoader?.pageChange(getCurrentFragment(), viewPagerBeans.size, position) onMojitoListener?.onViewPageSelected(position) } - }) if (!activityConfig.originImageUrls.isNullOrEmpty()) { - iIndicator?.attach(indicatorLayout) - iIndicator?.onShow(viewPager) + iIndicator?.attach(binding.indicatorLayout) + iIndicator?.onShow(binding.viewPager) } } fun setViewPagerLock(isLock: Boolean) { - viewPager.isLocked = isLock +// viewPager.isLocked = isLock + binding.viewPager.isUserInputEnabled = isLock } fun finishView() { @@ -158,9 +162,10 @@ class ImageMojitoActivity : AppCompatActivity(), IMojitoActivity { overridePendingTransition(0, 0) } + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { - (imageViewPagerAdapter.getItem(viewPager.currentItem) as ImageMojitoFragment).backToMin() + (getCurrentFragment() as ImageMojitoFragment).backToMin() true } else super.onKeyDown(keyCode, event) } @@ -176,7 +181,11 @@ class ImageMojitoActivity : AppCompatActivity(), IMojitoActivity { } override fun getCurrentFragment(): IMojitoFragment { - return imageViewPagerAdapter.getItem(viewPager.currentItem) as IMojitoFragment + return supportFragmentManager.findFragmentByTag( + "f" + imageViewPagerAdapter.getItemId( + binding.viewPager.currentItem + ) + ) as IMojitoFragment } override fun getContext(): Context { diff --git a/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoFragment.kt b/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoFragment.kt index ef8f6b9..44f9ce9 100644 --- a/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoFragment.kt +++ b/mojito/src/main/java/net/mikaelzero/mojito/ui/ImageMojitoFragment.kt @@ -9,13 +9,12 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import kotlinx.android.synthetic.main.fragment_image.* import net.mikaelzero.mojito.Mojito.Companion.imageLoader import net.mikaelzero.mojito.Mojito.Companion.imageViewFactory import net.mikaelzero.mojito.Mojito.Companion.mojitoConfig import net.mikaelzero.mojito.MojitoView -import net.mikaelzero.mojito.R import net.mikaelzero.mojito.bean.FragmentConfig +import net.mikaelzero.mojito.databinding.FragmentImageBinding import net.mikaelzero.mojito.interfaces.IMojitoFragment import net.mikaelzero.mojito.interfaces.IProgress import net.mikaelzero.mojito.interfaces.ImageViewLoadFactory @@ -28,6 +27,8 @@ import java.io.File class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { + private var _binding: FragmentImageBinding? = null + private val binding get() = _binding!! lateinit var fragmentConfig: FragmentConfig private var showView: View? = null private var mImageLoader: ImageLoader? = null @@ -38,7 +39,8 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { private var fragmentCoverLoader: FragmentCoverLoader? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_image, container, false) + _binding = FragmentImageBinding.inflate(inflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -56,35 +58,35 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { imageViewFactory() } fragmentCoverLoader = ImageMojitoActivity.fragmentCoverLoader?.providerInstance() - imageCoverLayout.removeAllViews() + binding.imageCoverLayout.removeAllViews() val fragmentCoverAttachView = fragmentCoverLoader?.attach(this, fragmentConfig.targetUrl == null || fragmentConfig.autoLoadTarget) if (fragmentCoverAttachView != null) { - imageCoverLayout.visibility = View.VISIBLE - imageCoverLayout.addView(fragmentCoverAttachView) + binding.imageCoverLayout.visibility = View.VISIBLE + binding.imageCoverLayout.addView(fragmentCoverAttachView) } else { - imageCoverLayout.visibility = View.GONE + binding.imageCoverLayout.visibility = View.GONE } iProgress = ImageMojitoActivity.progressLoader?.providerInstance() - iProgress?.attach(fragmentConfig.position, loadingLayout) + iProgress?.attach(fragmentConfig.position, binding.loadingLayout) contentLoader = mViewLoadFactory?.newContentLoader() - mojitoView.setBackgroundAlpha( + binding.mojitoView.setBackgroundAlpha( if (ImageMojitoActivity.hasShowedAnimMap[fragmentConfig.position] == true) 1f else if (fragmentConfig.showImmediately) 1f else 0f ) - mojitoView.setOnMojitoViewCallback(this) - mojitoView.setContentLoader(contentLoader, fragmentConfig.originUrl, fragmentConfig.targetUrl) + binding.mojitoView.setOnMojitoViewCallback(this) + binding.mojitoView.setContentLoader(contentLoader, fragmentConfig.originUrl, fragmentConfig.targetUrl) showView = contentLoader?.providerRealView() contentLoader?.onTapCallback(object : OnTapCallback { override fun onTap(view: View, x: Float, y: Float) { - mojitoView.backToMin() + binding.mojitoView.backToMin() ImageMojitoActivity.onMojitoListener?.onClick(view, x, y, fragmentConfig.position) } }) contentLoader?.onLongTapCallback(object : OnLongTapCallback { override fun onLongTap(view: View, x: Float, y: Float) { - if (!mojitoView.isDrag) { + if (!binding.mojitoView.isDrag) { ImageMojitoActivity.onMojitoListener?.onLongClick(activity, view, x, y, fragmentConfig.position) } } @@ -129,14 +131,14 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { ImageMojitoActivity.onMojitoListener?.onStartAnim(fragmentConfig.position) } if (fragmentConfig.viewParams == null) { - mojitoView?.showWithoutView(w, h, if (ImageMojitoActivity.hasShowedAnimMap[fragmentConfig.position] == true) true else fragmentConfig.showImmediately) + binding.mojitoView.showWithoutView(w, h, if (ImageMojitoActivity.hasShowedAnimMap[fragmentConfig.position] == true) true else fragmentConfig.showImmediately) } else { - mojitoView?.putData( + binding.mojitoView.putData( fragmentConfig.viewParams!!.getLeft(), fragmentConfig.viewParams!!.getTop(), fragmentConfig.viewParams!!.getWidth(), fragmentConfig.viewParams!!.getHeight(), w, h ) - mojitoView?.show(if (ImageMojitoActivity.hasShowedAnimMap[fragmentConfig.position] == true) true else fragmentConfig.showImmediately) + binding.mojitoView.show(if (ImageMojitoActivity.hasShowedAnimMap[fragmentConfig.position] == true) true else fragmentConfig.showImmediately) } val targetEnable = if (ImageMojitoActivity.multiContentLoader == null) { @@ -216,7 +218,7 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { } handleImageOnSuccess(image) val realSizes = getRealSizeFromFile(image) - mojitoView?.resetSize(realSizes[0], realSizes[1]) + binding.mojitoView.resetSize(realSizes[0], realSizes[1]) if (needHandleTarget) { replaceImageUrl(fragmentConfig.targetUrl!!) } @@ -230,8 +232,8 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { if (isDetached || context == null) { return@post } - if (loadingLayout?.visibility == View.GONE) { - loadingLayout?.visibility = View.VISIBLE + if (binding.loadingLayout.visibility == View.GONE) { + binding.loadingLayout.visibility = View.VISIBLE } iProgress?.onStart(fragmentConfig.position) } @@ -242,16 +244,16 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { if (isDetached || context == null) { return@post } - if (loadingLayout?.visibility == View.GONE) { - loadingLayout?.visibility = View.VISIBLE + if (binding.loadingLayout.visibility == View.GONE) { + binding.loadingLayout.visibility = View.VISIBLE } iProgress?.onProgress(fragmentConfig.position, progress) } } private fun handleImageOnSuccess(image: File) { - if (loadingLayout?.visibility == View.VISIBLE) { - loadingLayout?.visibility = View.GONE + if (binding.loadingLayout.visibility == View.VISIBLE) { + binding.loadingLayout.visibility = View.GONE } fragmentCoverLoader?.imageCacheHandle(isCache = true, hasTargetUrl = true) mViewLoadFactory?.loadSillContent(showView!!, Uri.fromFile(image)) @@ -291,8 +293,8 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { if (isDetached || context == null) { return@post } - if (loadingLayout?.visibility == View.GONE) { - loadingLayout?.visibility = View.VISIBLE + if (binding.loadingLayout.visibility == View.GONE) { + binding.loadingLayout.visibility = View.VISIBLE } iProgress?.onFailed(fragmentConfig.position) fragmentCoverLoader?.imageCacheHandle(isCache = false, hasTargetUrl = true) @@ -309,7 +311,7 @@ class ImageMojitoFragment : Fragment(), IMojitoFragment, OnMojitoViewCallback { } override fun backToMin() { - mojitoView?.backToMin() + binding.mojitoView.backToMin() } override fun providerContext(): Fragment { diff --git a/mojito/src/main/res/layout/activity_image.xml b/mojito/src/main/res/layout/activity_image.xml index 2ddf42f..d5286c6 100644 --- a/mojito/src/main/res/layout/activity_image.xml +++ b/mojito/src/main/res/layout/activity_image.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> -