diff --git a/build.gradle b/build.gradle index e4da491..c01f2f8 100644 --- a/build.gradle +++ b/build.gradle @@ -5,14 +5,19 @@ buildscript { google() mavenCentral() jcenter() + maven { url "https://jitpack.io" } } dependencies { classpath "com.android.tools.build:gradle:4.1.1" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - + classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' + classpath 'com.github.LukeXeon.android-iconfont-pipeline:iconfont-assets:ab8517244c' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } + ext { + groupId = 'com.github.LukeXeon' + } } allprojects { @@ -20,9 +25,12 @@ allprojects { google() mavenCentral() jcenter() + maven { url "https://jitpack.io" } } } task clean(type: Delete) { delete rootProject.buildDir -} \ No newline at end of file +} + + diff --git a/iconfont-app/build.gradle b/iconfont-app/build.gradle index 67f211d..bcce260 100644 --- a/iconfont-app/build.gradle +++ b/iconfont-app/build.gradle @@ -1,6 +1,10 @@ -plugins { - id 'com.android.application' - id 'kotlin-android' +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'open.source.iconfont.assets' + +iconfont { + host = 'https://icon-font-assets.oss-cn-beijing.aliyuncs.com' + version = '0.0.1' } android { diff --git a/iconfont-app/src/main/res/layout/activity_main.xml b/iconfont-app/src/main/res/layout/activity_main.xml index 7ee16c1..49837f5 100644 --- a/iconfont-app/src/main/res/layout/activity_main.xml +++ b/iconfont-app/src/main/res/layout/activity_main.xml @@ -2,19 +2,15 @@ + - - + app:srcCompat="@drawable/ref_daka_11" /> \ No newline at end of file diff --git a/iconfont-assets/build.gradle b/iconfont-assets/build.gradle index e3250f0..186a88e 100644 --- a/iconfont-assets/build.gradle +++ b/iconfont-assets/build.gradle @@ -1,8 +1,9 @@ apply plugin: 'java-gradle-plugin' apply plugin: 'groovy' apply plugin: 'maven' -version = '1.0.0' -group = 'open.source.iconfont' +apply plugin: 'maven-publish' + +group = rootProject.ext.groupId java { sourceCompatibility = JavaVersion.VERSION_1_7 @@ -14,3 +15,19 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' } + +afterEvaluate { + publishing { + publications { + // Creates a Maven publication called "release". + release(MavenPublication) { + from components.java + groupId = rootProject.ext.groupId + artifactId = 'iconfont-assets' + } + } + repositories { + mavenLocal() + } + } +} \ No newline at end of file diff --git a/iconfont-assets/src/main/java/open/source/iconfont/assets/GenAssetsPlugin.groovy b/iconfont-assets/src/main/groovy/open/source/iconfont/assets/GenAssetsPlugin.groovy similarity index 100% rename from iconfont-assets/src/main/java/open/source/iconfont/assets/GenAssetsPlugin.groovy rename to iconfont-assets/src/main/groovy/open/source/iconfont/assets/GenAssetsPlugin.groovy diff --git a/iconfont-assets/src/main/java/open/source/iconfont/assets/GenAssetsTask.groovy b/iconfont-assets/src/main/groovy/open/source/iconfont/assets/GenAssetsTask.groovy similarity index 85% rename from iconfont-assets/src/main/java/open/source/iconfont/assets/GenAssetsTask.groovy rename to iconfont-assets/src/main/groovy/open/source/iconfont/assets/GenAssetsTask.groovy index 822ab65..e20adcd 100644 --- a/iconfont-assets/src/main/java/open/source/iconfont/assets/GenAssetsTask.groovy +++ b/iconfont-assets/src/main/groovy/open/source/iconfont/assets/GenAssetsTask.groovy @@ -12,13 +12,12 @@ import retrofit2.converter.gson.GsonConverterFactory import java.nio.file.Paths import java.util.concurrent.Callable +import java.util.function.Function class GenAssetsTask extends DefaultTask { private final Gson gson - private static final int RETRY_TIME = 10 - GenAssetsTask() { gson = new Gson() } @@ -62,21 +61,15 @@ class GenAssetsTask extends DefaultTask { )) } - private T fetch(Callable callable) { - int count = 0 - def result - while (true) { - if (++count > RETRY_TIME) { - throw new IllegalStateException(project.extensions.iconfont.host + "出问题了,或者version不对") - } - try { - result = callable.call() - } catch (Throwable ignored) { - continue - } - if (result != null) { - break + private static T fetch(Callable callable, Function factory) { + def result = null + try { + result = callable.call() + if (result == null) { + throw new NullPointerException() } + } catch (Throwable e) { + throw factory.apply(e) } return result } @@ -121,6 +114,11 @@ class GenAssetsTask extends DefaultTask { } return null } + }, new Function() { + @Override + Throwable apply(Throwable throwable) { + return new IllegalStateException(host + "出问题了", throwable) + } }) def body = tuple.first def fontUrl = tuple.second @@ -136,6 +134,11 @@ class GenAssetsTask extends DefaultTask { } return null } + }, new Function() { + @Override + Throwable apply(Throwable throwable) { + return new IllegalStateException("拉取字体文件失败", throwable) + } }) def fontFile = getTypefaceFile() if (fontFile.exists()) { @@ -148,12 +151,11 @@ class GenAssetsTask extends DefaultTask { def xmlDir = getXmlDir() if (xmlDir.exists()) { xmlDir.deleteDir() - } else { - xmlDir.mkdir() } + xmlDir.mkdir() def fontName = getFontName() for (def item : body.icons) { - def name = toName(item.key) + def name = "ref_" + toName(item.key) def file = new File(xmlDir, name + ".xml") file.createNewFile() def writer = file.newWriter() @@ -173,6 +175,8 @@ class GenAssetsTask extends DefaultTask { def b = (byte) c if ((b >= 97 && b <= 122) || (b >= 65 && b <= 90)) { builder.append(c.toLowerCase()) + } else if (c.isDigit()) { + builder.append(c) } else if (i != 0 && i != source.length() - 1) { builder.append('_') } diff --git a/iconfont-assets/src/main/java/open/source/iconfont/assets/IconFontAsset.groovy b/iconfont-assets/src/main/groovy/open/source/iconfont/assets/IconFontAsset.groovy similarity index 100% rename from iconfont-assets/src/main/java/open/source/iconfont/assets/IconFontAsset.groovy rename to iconfont-assets/src/main/groovy/open/source/iconfont/assets/IconFontAsset.groovy diff --git a/iconfont-assets/src/main/java/open/source/iconfont/assets/IconFontAssetService.groovy b/iconfont-assets/src/main/groovy/open/source/iconfont/assets/IconFontAssetService.groovy similarity index 100% rename from iconfont-assets/src/main/java/open/source/iconfont/assets/IconFontAssetService.groovy rename to iconfont-assets/src/main/groovy/open/source/iconfont/assets/IconFontAssetService.groovy diff --git a/iconfont-assets/src/main/java/open/source/iconfont/assets/IconFontExtension.groovy b/iconfont-assets/src/main/groovy/open/source/iconfont/assets/IconFontExtension.groovy similarity index 100% rename from iconfont-assets/src/main/java/open/source/iconfont/assets/IconFontExtension.groovy rename to iconfont-assets/src/main/groovy/open/source/iconfont/assets/IconFontExtension.groovy diff --git a/iconfont-assets/src/main/java/resources/META-INF/gradle-plugins/open.source.iconfont.assets.properties b/iconfont-assets/src/main/resources/META-INF/gradle-plugins/open.source.iconfont.assets.properties similarity index 100% rename from iconfont-assets/src/main/java/resources/META-INF/gradle-plugins/open.source.iconfont.assets.properties rename to iconfont-assets/src/main/resources/META-INF/gradle-plugins/open.source.iconfont.assets.properties diff --git a/iconfont-assets/src/test/java/open/source/iconfont/assets/test/Main.java b/iconfont-assets/src/test/java/open/source/iconfont/assets/test/Main.java new file mode 100644 index 0000000..dfe51bc --- /dev/null +++ b/iconfont-assets/src/test/java/open/source/iconfont/assets/test/Main.java @@ -0,0 +1,31 @@ +package open.source.iconfont.assets.test; + +import com.google.gson.Gson; + +import java.io.IOException; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import open.source.iconfont.assets.IconFontAssetService; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +public class Main { + public static void main(String[] args) { + OkHttpClient client = new OkHttpClient(); + IconFontAssetService service = new Retrofit.Builder() + .client(client) + .baseUrl("https://icon-font-assets.oss-cn-beijing.aliyuncs.com") + .addConverterFactory(GsonConverterFactory.create(new Gson())) + .build() + .create(IconFontAssetService.class); + try { + System.out.println(service.index("0.0.1").execute().body().icons); + client.newCall(new Request.Builder() + .url("https://icon-font-assets.oss-cn-beijing.aliyuncs.com/icon-font-assets/iconfont.ttf") + .build()).execute(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/iconfont-export/.gitignore b/iconfont-export/.gitignore index 6f8a813..62f9bec 100644 --- a/iconfont-export/.gitignore +++ b/iconfont-export/.gitignore @@ -1,2 +1,4 @@ -/build -/.idea \ No newline at end of file +/node_modules +yarn.lock +/.idea +/build \ No newline at end of file diff --git a/iconfont-export/assets/icons/daka-11.svg b/iconfont-export/assets/icons/daka-11.svg new file mode 100644 index 0000000..2be6d96 --- /dev/null +++ b/iconfont-export/assets/icons/daka-11.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/iconfont-export/assets/icons/fenxiang-05.svg b/iconfont-export/assets/icons/fenxiang-05.svg new file mode 100644 index 0000000..9e1b2ac --- /dev/null +++ b/iconfont-export/assets/icons/fenxiang-05.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/iconfont-export/assets/icons/sousuo-02.svg b/iconfont-export/assets/icons/sousuo-02.svg new file mode 100644 index 0000000..47e0791 --- /dev/null +++ b/iconfont-export/assets/icons/sousuo-02.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/iconfont-export/assets/icons/xiaoxi-03.svg b/iconfont-export/assets/icons/xiaoxi-03.svg new file mode 100644 index 0000000..45db76b --- /dev/null +++ b/iconfont-export/assets/icons/xiaoxi-03.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/iconfont-export/gulpfile.js b/iconfont-export/gulpfile.js new file mode 100644 index 0000000..e2b1c24 --- /dev/null +++ b/iconfont-export/gulpfile.js @@ -0,0 +1,73 @@ +const iconfont = require('gulp-iconfont'); +const gulp = require('gulp'); +const fs = require('fs'); +const del = require('del'); +const path = require('path'); +const argv = require('minimist')(process.argv.slice(2)); +const input = argv['input'] || "assets/icons"; +const output = argv['output'] || 'build/'; +const fontName = argv['font-name'] || 'iconfont'; +const version = argv['version'] || '0.0.1'; +const outputWithVersion = path.join(output, version); + +/* Creates a unicode literal based on the string */ +function unicodeLiteral(str) { + function fixedHex(number, length) { + let str = number.toString(16).toUpperCase(); + while (str.length < length) + str = "0" + str; + return str; + } + + let i; + let result = ""; + for (i = 0; i < str.length; ++i) { + /* You should probably replace this by an isASCII test */ + if (str.charCodeAt(i) > 126 || str.charCodeAt(i) < 32) + result += fixedHex(str.charCodeAt(i), 4); + else + result += str[i]; + } + + return result.toLocaleLowerCase(); +} + +function saveJson(list) { + const icons = {}; + for (let e of list) { + icons[e.name] = e.unicode + } + const json = {icons, version, fonts: ["./" + fontName + ".ttf"]}; + const exportJson = path.join(outputWithVersion, "export.json"); + if (fs.existsSync(exportJson)) { + fs.unlinkSync(exportJson); + } + fs.writeFileSync(exportJson, JSON.stringify(json)); +} + +gulp.task('clean', async () => { + await del([ + path.join(output, '/**/*'), + ]); +}); + +gulp.task('iconfont', () => { + return gulp.src([path.join(input, '*.svg')]) + .pipe(iconfont({ + fontName: fontName, + formats: ['ttf'], + })) + .on('glyphs', function (glyphs, options) { + // CSS templating, e.g. + saveJson(glyphs.map((e) => { + return { + name: e.name, + unicode: unicodeLiteral(e.unicode[0]) + } + })); + //console.log(glyphs, options); + }) + .pipe(gulp.dest(outputWithVersion)); +}); + +gulp.task("default", gulp.series("clean", "iconfont")); diff --git a/iconfont-export/package.json b/iconfont-export/package.json index b71f2da..6e832ed 100644 --- a/iconfont-export/package.json +++ b/iconfont-export/package.json @@ -1,20 +1,20 @@ { - "name": "iconfont-export", + "name": "svg2iconfont", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "iconfont": "gulp default" }, + "keywords": [], + "author": "", + "license": "ISC", "dependencies": { + "del": "^6.0.0", "gulp": "^4.0.2", "gulp-filter": "^6.0.0", "gulp-iconfont": "^11.0.0", - "hasha": "^5.2.2", - "minimist": "^1.2.5", - "xmldom": "^0.4.0" - }, - "keywords": [], - "author": "", - "license": "ISC" + "minimist": "^1.2.5" + } } diff --git a/iconfont/build.gradle b/iconfont/build.gradle index 78b2868..5554d92 100644 --- a/iconfont/build.gradle +++ b/iconfont/build.gradle @@ -1,7 +1,8 @@ -plugins { - id 'com.android.library' - id 'kotlin-android' -} +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'com.github.dcendents.android-maven' + +group = rootProject.ext.groupId android { compileSdkVersion 30 @@ -33,10 +34,10 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' -} \ No newline at end of file +} + diff --git a/iconfont/src/main/java/open/source/iconfont/IconTextDrawable.kt b/iconfont/src/main/java/open/source/iconfont/IconTextDrawable.kt index c67921e..c298210 100644 --- a/iconfont/src/main/java/open/source/iconfont/IconTextDrawable.kt +++ b/iconfont/src/main/java/open/source/iconfont/IconTextDrawable.kt @@ -37,17 +37,12 @@ class IconTextDrawable : Drawable, TintAwareDrawable { private const val CODE_CACHE_SIZE = 128 - private val localContext = ThreadLocal() - private val codes = object : LruCache(CODE_CACHE_SIZE) { override fun create(key: String): String { return key.toInt(16).toChar().toString() } } - private val inflateContext: Context - get() = localContext.get() ?: AppCompatUtils.application - @JvmStatic fun create( context: Context, @@ -84,16 +79,6 @@ class IconTextDrawable : Drawable, TintAwareDrawable { return IconTextDrawable().apply { inflate(context, parser, attrs, theme) } } - @JvmStatic - fun withContext(context: Context, action: Runnable) { - try { - localContext.set(context) - action.run() - } finally { - localContext.set(null) - } - } - /** * Parses a [android.graphics.PorterDuff.Mode] from a tintMode * attribute's enum value. @@ -240,6 +225,15 @@ class IconTextDrawable : Drawable, TintAwareDrawable { shadowRadius = other.shadowRadius paint.set(other.paint) padding.set(other.padding) + centerX = other.centerX + centerY = other.centerY + useLevel = other.useLevel + angle = other.angle + orientation = other.orientation + gradientColors = other.gradientColors + positions = other.positions + gradientType = other.gradientType + gradientRadius = other.gradientRadius } override fun newDrawable(): Drawable { @@ -323,7 +317,7 @@ class IconTextDrawable : Drawable, TintAwareDrawable { parser: XmlPullParser, attrs: AttributeSet ) { - inflate(inflateContext, parser, attrs, null) + inflate(r, parser, attrs, null) } override fun inflate( @@ -332,7 +326,7 @@ class IconTextDrawable : Drawable, TintAwareDrawable { attrs: AttributeSet, theme: Theme? ) { - inflate(inflateContext, parser, attrs, theme) + inflate(InflateContext.obtain(r), parser, attrs, theme) } fun inflate( @@ -343,6 +337,7 @@ class IconTextDrawable : Drawable, TintAwareDrawable { ) { val array = obtainAttributes(context.resources, theme, attrs, R.styleable.IconTextDrawable) try { + setVisible(array.getBoolean(R.styleable.IconTextDrawable_visible, true), false) val text = array.getString(R.styleable.IconTextDrawable_code) if (!text.isNullOrEmpty()) { state.text = codes[text] @@ -807,10 +802,13 @@ class IconTextDrawable : Drawable, TintAwareDrawable { return field } set(@Px value) { - field = 0f - state.gradientRadius = value - gradientIsDirty = true - invalidateSelf() + if (Throwable().stackTrace.first().className != IconTextDrawable::class.java.name) { + state.gradientRadius = value + gradientIsDirty = true + invalidateSelf() + } else { + field = value + } } var gradientType: Int diff --git a/iconfont/src/main/java/open/source/iconfont/InflateContext.kt b/iconfont/src/main/java/open/source/iconfont/InflateContext.kt new file mode 100644 index 0000000..249c8d0 --- /dev/null +++ b/iconfont/src/main/java/open/source/iconfont/InflateContext.kt @@ -0,0 +1,36 @@ +package open.source.iconfont + +import android.content.Context +import android.content.ContextWrapper +import android.content.res.AssetManager +import android.content.res.Resources +import java.lang.ref.WeakReference +import java.util.* + +internal class InflateContext( + base: Context, + res: Resources +) : ContextWrapper(base) { + + private val reference = WeakReference(res) + + override fun getResources(): Resources { + return reference.get() ?: super.getResources() + } + + override fun getAssets(): AssetManager { + return resources.assets + } + + companion object { + private val caches = WeakHashMap() + + fun obtain(r: Resources): Context { + synchronized(caches) { + return caches.getOrPut(r) { + InflateContext(AppCompatUtils.application, r) + } + } + } + } +} \ No newline at end of file diff --git a/iconfont/src/main/java/open/source/iconfont/Ktx.kt b/iconfont/src/main/java/open/source/iconfont/Ktx.kt new file mode 100644 index 0000000..49f6721 --- /dev/null +++ b/iconfont/src/main/java/open/source/iconfont/Ktx.kt @@ -0,0 +1,16 @@ +package open.source.iconfont + +import android.content.Context +import android.content.res.Resources +import android.graphics.drawable.Drawable +import androidx.annotation.DrawableRes +import androidx.annotation.XmlRes +import androidx.appcompat.content.res.AppCompatResources + +fun Context.getAppCompatDrawable(@XmlRes @DrawableRes resId: Int): Drawable? { + return AppCompatResources.getDrawable(this, resId) +} + +fun Resources.getAppCompatDrawable(@XmlRes @DrawableRes resId: Int): Drawable? { + return AppCompatResources.getDrawable(InflateContext.obtain(this), resId) +} \ No newline at end of file diff --git a/iconfont/src/main/res/values/values.xml b/iconfont/src/main/res/values/values.xml index dfe5f7d..915fb86 100644 --- a/iconfont/src/main/res/values/values.xml +++ b/iconfont/src/main/res/values/values.xml @@ -1,6 +1,7 @@ +