mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-17 04:00:48 +01:00
improved QR code style
This commit is contained in:
parent
fe9ee01765
commit
0aaeb32141
@ -62,6 +62,7 @@ subprojects {
|
||||
Kovenant : '3.3.0',
|
||||
ParcelablePlease : '1.0.2',
|
||||
Chameleon : '0.9.17',
|
||||
UniqR : '0.9',
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,8 @@ android {
|
||||
applicationId "org.mariotaku.twidere"
|
||||
minSdkVersion project.properties['overrideMinSdkVersion'] ?: 14
|
||||
targetSdkVersion 25
|
||||
versionCode 322
|
||||
versionName '3.5.5'
|
||||
versionCode 323
|
||||
versionName '3.5.6'
|
||||
multiDexEnabled true
|
||||
|
||||
buildConfigField 'boolean', 'LEAK_CANARY_ENABLED', 'Boolean.parseBoolean("true")'
|
||||
@ -138,6 +138,7 @@ dependencies {
|
||||
compile "com.android.support:recyclerview-v7:${libVersions['SupportLib']}"
|
||||
compile "com.android.support:preference-v7:${libVersions['SupportLib']}"
|
||||
compile "com.android.support:preference-v14:${libVersions['SupportLib']}"
|
||||
compile "com.android.support:palette-v7:${libVersions['SupportLib']}"
|
||||
compile "com.android.support:customtabs:${libVersions['SupportLib']}"
|
||||
compile "com.android.support:design:${libVersions['SupportLib']}"
|
||||
compile "com.android.support:percent:${libVersions['SupportLib']}"
|
||||
@ -188,7 +189,7 @@ dependencies {
|
||||
compile "com.github.mariotaku:KPreferences:${libVersions['KPreferences']}"
|
||||
compile "com.github.mariotaku:Chameleon:${libVersions['Chameleon']}"
|
||||
compile 'com.github.mariotaku.QR-Code-generator:core:fcab3ea7f4'
|
||||
compile 'com.github.mariotaku.QR-Code-generator:android:fcab3ea7f4'
|
||||
compile 'com.github.mariotaku.UniqR:android:0.9'
|
||||
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:${libVersions['Kotlin']}"
|
||||
compile "nl.komponents.kovenant:kovenant:${libVersions['Kovenant']}"
|
||||
|
@ -19,12 +19,16 @@
|
||||
|
||||
package org.mariotaku.twidere.annotation;
|
||||
|
||||
import android.support.annotation.StringDef;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/3/6.
|
||||
*/
|
||||
|
||||
@StringDef({ProfileImageSize.NORMAL, ProfileImageSize.BIGGER, ProfileImageSize.REASONABLY_SMALL,
|
||||
ProfileImageSize.ORIGINAL})
|
||||
public @interface ProfileImageSize {
|
||||
String REASONABLY_SMALL = "reasonably_small";
|
||||
String BIGGER = "bigger";
|
||||
String NORMAL = "normal";
|
||||
String ORIGINAL = "original";
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ import org.mariotaku.sqliteqb.library.Selectable;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.annotation.CustomTabType;
|
||||
import org.mariotaku.twidere.annotation.ProfileImageSize;
|
||||
import org.mariotaku.twidere.extension.model.AccountDetailsExtensionsKt;
|
||||
import org.mariotaku.twidere.model.AccountDetails;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
@ -563,6 +564,9 @@ public final class Utils implements Constants {
|
||||
|
||||
|
||||
public static String getTwitterProfileImageOfSize(@NonNull final String url, @NonNull final String size) {
|
||||
if (ProfileImageSize.ORIGINAL.equals(size)) {
|
||||
return getOriginalTwitterProfileImage(url);
|
||||
}
|
||||
final Matcher matcher = PATTERN_TWITTER_PROFILE_IMAGES.matcher(url);
|
||||
if (matcher.matches()) {
|
||||
return matcher.replaceFirst("$1$2/profile_images/$3/$4_" + size + "$6");
|
||||
|
@ -94,6 +94,7 @@ import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.twitter.model.FriendshipUpdate
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.UserList
|
||||
import org.mariotaku.twidere.BuildConfig
|
||||
import org.mariotaku.twidere.Constants.*
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.activity.AccountSelectorActivity
|
||||
@ -832,7 +833,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
|
||||
mentionItem.title = getString(R.string.mention_user_name, displayName)
|
||||
}
|
||||
MenuUtils.setItemAvailability(menu, R.id.mention, !isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.qr_code, isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.qr_code, isMyself || BuildConfig.DEBUG)
|
||||
MenuUtils.setItemAvailability(menu, R.id.incoming_friendships, isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.saved_searches, isMyself)
|
||||
|
||||
|
@ -19,24 +19,37 @@
|
||||
|
||||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Bundle
|
||||
import android.support.v7.graphics.Palette
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import com.bumptech.glide.Glide
|
||||
import io.nayuki.qrcodegen.QrCode
|
||||
import io.nayuki.qrcodegen.QrCodeAndroid
|
||||
import io.nayuki.qrcodegen.QrSegment
|
||||
import kotlinx.android.synthetic.main.fragment_user_qr.*
|
||||
import nl.komponents.kovenant.combine.and
|
||||
import nl.komponents.kovenant.then
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.promiseOnUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.annotation.ProfileImageSize
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER
|
||||
import org.mariotaku.twidere.extension.loadProfileImage
|
||||
import org.mariotaku.twidere.model.ParcelableUser
|
||||
import org.mariotaku.twidere.util.LinkCreator
|
||||
import org.mariotaku.twidere.util.TwidereColorUtils
|
||||
import org.mariotaku.twidere.util.glide.DeferredTarget
|
||||
import org.mariotaku.twidere.util.qr.QrCodeData
|
||||
import org.mariotaku.uniqr.AndroidPlatform
|
||||
import org.mariotaku.uniqr.UniqR
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/3.
|
||||
@ -52,16 +65,72 @@ class UserQRDialogFragment : BaseDialogFragment() {
|
||||
|
||||
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val qrCode = QrCode.encodeText(LinkCreator.getUserWebLink(user).toString(), QrCode.Ecc.HIGH)
|
||||
val bitmap = QrCodeAndroid.toBitmap(qrCode, 1, 0, Bitmap.Config.ARGB_8888)
|
||||
val profileImageSize = getString(R.string.profile_image_size)
|
||||
qrView.setImageDrawable(BitmapDrawable(resources, bitmap).apply {
|
||||
this.setAntiAlias(false)
|
||||
this.isFilterBitmap = false
|
||||
})
|
||||
profileImage.setShapeBackground(Color.WHITE)
|
||||
Glide.with(this).loadProfileImage(context, user, profileImage.style, profileImage.cornerRadius,
|
||||
profileImage.cornerRadiusRatio, profileImageSize).into(profileImage)
|
||||
|
||||
val weakThis = WeakReference(this)
|
||||
val deferred = Glide.with(this).loadProfileImage(context, user, 0, 0f, 0f,
|
||||
ProfileImageSize.ORIGINAL).into(DeferredTarget())
|
||||
promiseOnUi {
|
||||
val fragment = weakThis.get() ?: return@promiseOnUi
|
||||
fragment.qrView.visibility = View.INVISIBLE
|
||||
fragment.qrProgress.visibility = View.VISIBLE
|
||||
} and deferred.promise.then { drawable ->
|
||||
val fragment = weakThis.get() ?: throw InterruptedException()
|
||||
val background = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight,
|
||||
Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(background)
|
||||
drawable.setBounds(0, 0, background.width, background.height)
|
||||
drawable.draw(canvas)
|
||||
|
||||
val palette = Palette.from(background).generate()
|
||||
|
||||
val qrData = run {
|
||||
val segments = QrSegment.makeSegments(LinkCreator.getUserWebLink(fragment.user).toString())
|
||||
return@run QrCodeData(QrCode.encodeSegments(segments, QrCode.Ecc.HIGH, 5, 40, -1, true))
|
||||
}
|
||||
val uniqr = UniqR(AndroidPlatform(), background, qrData)
|
||||
uniqr.setScale(3)
|
||||
uniqr.setQrPatternColor(palette.patternColor)
|
||||
val result = uniqr.build().produceResult()
|
||||
background.recycle()
|
||||
return@then result
|
||||
}.successUi { bitmap ->
|
||||
val fragment = weakThis.get() ?: return@successUi
|
||||
fragment.qrView.visibility = View.VISIBLE
|
||||
fragment.qrProgress.visibility = View.GONE
|
||||
fragment.qrView.setImageDrawable(BitmapDrawable(fragment.resources, bitmap).apply {
|
||||
this.setAntiAlias(false)
|
||||
this.isFilterBitmap = false
|
||||
})
|
||||
}.failUi {
|
||||
val fragment = weakThis.get() ?: return@failUi
|
||||
Toast.makeText(fragment.context, R.string.message_toast_error_occurred, Toast.LENGTH_SHORT).show()
|
||||
fragment.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun getOptimalPatternColor(color: Int): Int {
|
||||
val yiq = IntArray(3)
|
||||
TwidereColorUtils.colorToYIQ(color, yiq)
|
||||
if (yiq[0] > 72) {
|
||||
yiq[0] = 72
|
||||
return TwidereColorUtils.YIQToColor(Color.alpha(color), yiq)
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
private val Palette.patternColor: Int get() {
|
||||
var color = getDarkVibrantColor(0)
|
||||
if (color == 0) {
|
||||
color = getDominantColor(0)
|
||||
}
|
||||
if (color == 0) {
|
||||
color = getDarkMutedColor(0)
|
||||
}
|
||||
if (color == 0) {
|
||||
return Color.BLACK
|
||||
}
|
||||
return getOptimalPatternColor(color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,35 +17,25 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.graphic
|
||||
package org.mariotaku.twidere.util.qr
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.drawable.Drawable
|
||||
import io.nayuki.qrcodegen.QrCode
|
||||
import org.mariotaku.uniqr.QrData
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/3.
|
||||
* Created by mariotaku on 2017/4/10.
|
||||
*/
|
||||
data class QrCodeData(private val qrCode: QrCode) : QrData {
|
||||
|
||||
class QrCodeDrawable(val qrCode: QrCode) : Drawable() {
|
||||
override fun draw(canvas: Canvas) {
|
||||
for (x in 0 until qrCode.size) {
|
||||
for (y in 0 until qrCode.size) {
|
||||
|
||||
}
|
||||
}
|
||||
override fun getSize(): Int {
|
||||
return qrCode.size
|
||||
}
|
||||
|
||||
override fun getOpacity() = PixelFormat.OPAQUE
|
||||
|
||||
override fun setAlpha(alpha: Int) {
|
||||
// NO-OP
|
||||
override fun getVersion(): Int {
|
||||
return qrCode.version
|
||||
}
|
||||
|
||||
override fun setColorFilter(colorFilter: ColorFilter?) {
|
||||
// NO-OP
|
||||
override fun get(x: Int, y: Int): Boolean {
|
||||
return qrCode.getModule(x, y) == 1
|
||||
}
|
||||
|
||||
}
|
@ -20,7 +20,6 @@
|
||||
|
||||
<org.mariotaku.twidere.view.SquareRelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
@ -38,14 +37,10 @@
|
||||
android:padding="@dimen/element_spacing_xlarge"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<org.mariotaku.twidere.view.ProfileImageView
|
||||
android:id="@+id/profileImage"
|
||||
style="?profileImageStyle"
|
||||
android:layout_width="@dimen/element_size_mlarge"
|
||||
android:layout_height="@dimen/element_size_mlarge"
|
||||
android:layout_centerInParent="true"
|
||||
app:sivBorderColor="@android:color/white"
|
||||
app:sivBorderWidth="2dp"
|
||||
app:sivShape="rectangle"/>
|
||||
<ProgressBar
|
||||
android:id="@+id/qrProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"/>
|
||||
|
||||
</org.mariotaku.twidere.view.SquareRelativeLayout>
|
Loading…
x
Reference in New Issue
Block a user