From 00e411b1e3a05ff019e23f520167f6f17e5715a7 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 20 May 2017 21:46:47 +0200 Subject: [PATCH] display keyserver status on card --- .../keychain/ui/keyview/ViewKeyFragment.java | 11 ++ .../keyview/loader/KeyserverStatusLoader.java | 136 ++++++++++++++++++ .../presenter/KeyserverStatusPresenter.java | 103 +++++++++++++ .../keyview/view/KeyserverStatusCardView.java | 124 ++++++++++++++++ .../res/drawable-hdpi/ic_cloud_off_24dp.png | Bin 0 -> 630 bytes .../drawable-hdpi/ic_cloud_unknown_24dp.png | Bin 0 -> 608 bytes .../res/drawable-mdpi/ic_cloud_off_24dp.png | Bin 0 -> 454 bytes .../drawable-mdpi/ic_cloud_unknown_24dp.png | Bin 0 -> 434 bytes .../res/drawable-xhdpi/ic_cloud_off_24dp.png | Bin 0 -> 834 bytes .../drawable-xhdpi/ic_cloud_unknown_24dp.png | Bin 0 -> 758 bytes .../res/drawable-xxhdpi/ic_cloud_off_24dp.png | Bin 0 -> 1228 bytes .../drawable-xxhdpi/ic_cloud_unknown_24dp.png | Bin 0 -> 1126 bytes .../drawable-xxxhdpi/ic_cloud_off_24dp.png | Bin 0 -> 1619 bytes .../ic_cloud_unknown_24dp.png | Bin 0 -> 1489 bytes .../res/layout/key_keyserver_card_content.xml | 78 ++++++++++ OpenKeychain/src/main/res/values/strings.xml | 5 + graphics/drawables/ic_cloud_off.svg | 4 + graphics/drawables/ic_cloud_unknown.svg | 59 ++++++++ graphics/update-drawables.sh | 2 +- 19 files changed, 521 insertions(+), 1 deletion(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/KeyserverStatusCardView.java create mode 100644 OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_off_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_unknown_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-mdpi/ic_cloud_off_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-mdpi/ic_cloud_unknown_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xhdpi/ic_cloud_off_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xhdpi/ic_cloud_unknown_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxhdpi/ic_cloud_off_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxhdpi/ic_cloud_unknown_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxxhdpi/ic_cloud_off_24dp.png create mode 100644 OpenKeychain/src/main/res/drawable-xxxhdpi/ic_cloud_unknown_24dp.png create mode 100644 OpenKeychain/src/main/res/layout/key_keyserver_card_content.xml create mode 100644 graphics/drawables/ic_cloud_off.svg create mode 100644 graphics/drawables/ic_cloud_unknown.svg diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java index bd61897c1..03e774f34 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java @@ -40,6 +40,8 @@ import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView; import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView; import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView; import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView; +import org.sufficientlysecure.keychain.ui.keyview.view.KeyserverStatusCardView; +import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter; public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { @@ -51,6 +53,7 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { private static final int LOADER_IDENTITIES = 1; private static final int LOADER_ID_LINKED_CONTACT = 2; private static final int LOADER_ID_SUBKEY_STATUS = 3; + private static final int LOADER_ID_KEYSERVER_STATUS = 4; private IdentitiesCardView mIdentitiesCardView; private IdentitiesPresenter mIdentitiesPresenter; @@ -62,6 +65,9 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { KeyHealthPresenter mKeyHealthPresenter; + KeyserverStatusCardView mKeyserverStatusCard; + KeyserverStatusPresenter mKeyserverStatusPresenter; + /** * Creates new instance of this fragment */ @@ -85,6 +91,7 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { mSystemContactCard = (SystemContactCardView) view.findViewById(R.id.linked_system_contact_card); mKeyStatusHealth = (KeyHealthView) view.findViewById(R.id.key_status_health); + mKeyserverStatusCard = (KeyserverStatusCardView) view.findViewById(R.id.keyserver_status_card); return root; } @@ -107,6 +114,10 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { mKeyHealthPresenter = new KeyHealthPresenter( getContext(), mKeyStatusHealth, LOADER_ID_SUBKEY_STATUS, masterKeyId, mIsSecret); mKeyHealthPresenter.startLoader(getLoaderManager()); + + mKeyserverStatusPresenter = new KeyserverStatusPresenter( + getContext(), mKeyserverStatusCard, LOADER_ID_KEYSERVER_STATUS, masterKeyId, mIsSecret); + mKeyserverStatusPresenter.startLoader(getLoaderManager()); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java new file mode 100644 index 000000000..8cd59f934 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/KeyserverStatusLoader.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2017 Vincent Breitmoser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.ui.keyview.loader; + + +import java.util.Date; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.support.v4.content.AsyncTaskLoader; +import android.util.Log; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys; +import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusLoader.KeyserverStatus; + + +public class KeyserverStatusLoader extends AsyncTaskLoader { + public static final String[] PROJECTION = new String[] { + UpdatedKeys.LAST_UPDATED, + UpdatedKeys.SEEN_ON_KEYSERVERS + }; + private static final int INDEX_LAST_UPDATED = 0; + private static final int INDEX_SEEN_ON_KEYSERVERS = 1; + + + private final ContentResolver contentResolver; + private final long masterKeyId; + + private KeyserverStatus cachedResult; + + + public KeyserverStatusLoader(Context context, ContentResolver contentResolver, long masterKeyId) { + super(context); + + this.contentResolver = contentResolver; + this.masterKeyId = masterKeyId; + } + + @Override + public KeyserverStatus loadInBackground() { + Cursor cursor = contentResolver.query(UpdatedKeys.CONTENT_URI, PROJECTION, + UpdatedKeys.MASTER_KEY_ID + " = ?", new String[] { Long.toString(masterKeyId) }, null); + if (cursor == null) { + Log.e(Constants.TAG, "Error loading key items!"); + return null; + } + + try { + if (cursor.moveToFirst()) { + boolean isPublished = cursor.getInt(INDEX_SEEN_ON_KEYSERVERS) != 0; + Date lastUpdated = cursor.isNull(INDEX_LAST_UPDATED) ? + null : new Date(cursor.getLong(INDEX_LAST_UPDATED) * 1000); + + return new KeyserverStatus(masterKeyId, isPublished, lastUpdated); + } + + return new KeyserverStatus(masterKeyId); + } finally { + cursor.close(); + } + } + + @Override + public void deliverResult(KeyserverStatus keySubkeyStatus) { + cachedResult = keySubkeyStatus; + + if (isStarted()) { + super.deliverResult(keySubkeyStatus); + } + } + + @Override + protected void onStartLoading() { + if (cachedResult != null) { + deliverResult(cachedResult); + } + + if (takeContentChanged() || cachedResult == null) { + forceLoad(); + } + } + + public static class KeyserverStatus { + private final long masterKeyId; + private final boolean isPublished; + private final Date lastUpdated; + + KeyserverStatus(long masterKeyId, boolean isPublished, Date lastUpdated) { + this.masterKeyId = masterKeyId; + this.isPublished = isPublished; + this.lastUpdated = lastUpdated; + } + + KeyserverStatus(long masterKeyId) { + this.masterKeyId = masterKeyId; + this.isPublished = false; + this.lastUpdated = null; + } + + long getMasterKeyId() { + return masterKeyId; + } + + public boolean hasBeenUpdated() { + return lastUpdated != null; + } + + public boolean isPublished() { + if (lastUpdated == null) { + throw new IllegalStateException("Cannot get publication state if key has never been updated!"); + } + return isPublished; + } + + public Date getLastUpdated() { + return lastUpdated; + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java new file mode 100644 index 000000000..c3c248a22 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/KeyserverStatusPresenter.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 Vincent Breitmoser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.ui.keyview.presenter; + + +import java.util.Date; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; + +import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusLoader; +import org.sufficientlysecure.keychain.ui.keyview.loader.KeyserverStatusLoader.KeyserverStatus; + + +public class KeyserverStatusPresenter implements LoaderCallbacks { + private final Context context; + private final KeyserverStatusMvpView view; + private final int loaderId; + + private final long masterKeyId; + private final boolean isSecret; + + + public KeyserverStatusPresenter(Context context, KeyserverStatusMvpView view, int loaderId, long masterKeyId, + boolean isSecret) { + this.context = context; + this.view = view; + this.loaderId = loaderId; + + this.masterKeyId = masterKeyId; + this.isSecret = isSecret; + + view.setOnKeyserverClickListener(new KeyserverStatusClickListener() { + @Override + public void onKeyRefreshClick() { + KeyserverStatusPresenter.this.onKeyRefreshClick(); + } + }); + } + + public void startLoader(LoaderManager loaderManager) { + loaderManager.restartLoader(loaderId, null, this); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new KeyserverStatusLoader(context, context.getContentResolver(), masterKeyId); + } + + @Override + public void onLoadFinished(Loader loader, KeyserverStatus keyserverStatus) { + if (keyserverStatus.hasBeenUpdated()) { + if (keyserverStatus.isPublished()) { + view.setDisplayStatusPublished(); + } else { + view.setDisplayStatusNotPublished(); + } + view.setLastUpdated(keyserverStatus.getLastUpdated()); + } else { + view.setDisplayStatusUnknown(); + } + } + + @Override + public void onLoaderReset(Loader loader) { + + } + + private void onKeyRefreshClick() { + + } + + public interface KeyserverStatusMvpView { + void setOnKeyserverClickListener(KeyserverStatusClickListener keyserverStatusClickListener); + + void setDisplayStatusPublished(); + void setDisplayStatusNotPublished(); + void setLastUpdated(Date lastUpdated); + void setDisplayStatusUnknown(); + } + + public interface KeyserverStatusClickListener { + void onKeyRefreshClick(); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/KeyserverStatusCardView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/KeyserverStatusCardView.java new file mode 100644 index 000000000..2dcb2155b --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/KeyserverStatusCardView.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2017 Vincent Breitmoser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.ui.keyview.view; + + +import java.util.Date; + +import android.content.Context; +import android.support.annotation.ColorRes; +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.CardView; +import android.text.format.DateFormat; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter.KeyserverStatusClickListener; +import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter.KeyserverStatusMvpView; + + +public class KeyserverStatusCardView extends CardView implements KeyserverStatusMvpView, OnClickListener { + private final View vLayout; + private final TextView vTitle; + private final TextView vSubtitle; + private final ImageView vIcon; + + private KeyserverStatusClickListener keyHealthClickListener; + + public KeyserverStatusCardView(Context context, AttributeSet attrs) { + super(context, attrs); + + View view = LayoutInflater.from(context).inflate(R.layout.key_keyserver_card_content, this, true); + + vLayout = view.findViewById(R.id.key_health_layout); + + vTitle = (TextView) view.findViewById(R.id.keyserver_status_title); + vSubtitle = (TextView) view.findViewById(R.id.keyserver_status_subtitle); + vIcon = (ImageView) view.findViewById(R.id.keyserver_icon); +// vExpander = (ImageView) view.findViewById(R.id.key_health_expander); + } + + private enum KeyserverDisplayStatus { + PUBLISHED (R.string.keyserver_title_published, R.drawable.ic_cloud_black_24dp, R.color.md_grey_900), + NOT_PUBLISHED (R.string.keyserver_title_not_published, R.drawable.ic_cloud_off_24dp, R.color.md_grey_900), + UNKNOWN (R.string.keyserver_title_unknown, R.drawable.ic_cloud_unknown_24dp, R.color.md_grey_900); + + @StringRes + private final int title; + @DrawableRes + private final int icon; + @ColorRes + private final int iconColor; + + KeyserverDisplayStatus(@StringRes int title, @DrawableRes int icon, @ColorRes int iconColor) { + this.title = title; + this.icon = icon; + this.iconColor = iconColor; + } + } + + @Override + public void onClick(View view) { + if (keyHealthClickListener != null) { + keyHealthClickListener.onKeyRefreshClick(); + } + } + + @Override + public void setOnKeyserverClickListener(KeyserverStatusClickListener keyHealthClickListener) { + this.keyHealthClickListener = keyHealthClickListener; + vLayout.setClickable(keyHealthClickListener != null); + } + + @Override + public void setDisplayStatusPublished() { + setDisplayStatus(KeyserverDisplayStatus.PUBLISHED); + } + + @Override + public void setDisplayStatusNotPublished() { + setDisplayStatus(KeyserverDisplayStatus.NOT_PUBLISHED); + } + + @Override + public void setDisplayStatusUnknown() { + setDisplayStatus(KeyserverDisplayStatus.UNKNOWN); + vSubtitle.setVisibility(View.GONE); + } + + @Override + public void setLastUpdated(Date lastUpdated) { + String lastUpdatedText = DateFormat.getMediumDateFormat(getContext()).format(lastUpdated); + vSubtitle.setText(getResources().getString(R.string.keyserver_last_updated, lastUpdatedText)); + } + + private void setDisplayStatus(KeyserverDisplayStatus displayStatus) { + vTitle.setText(displayStatus.title); + vIcon.setImageResource(displayStatus.icon); + vIcon.setColorFilter(ContextCompat.getColor(getContext(), displayStatus.iconColor)); + + setVisibility(View.VISIBLE); + } +} diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_off_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_off_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..fabb499c711cdeeffa6fc8ac185e115a188aabcf GIT binary patch literal 630 zcmV-+0*U>JP)jK~z|U?bkbN6j2z)@t>DM)I!t+5k$fDf)d3hSi~Y;8f{Wp z`T<1n8>p3qRkYJo))uZGKnW=cHqorFLTRIvk#o+oc9_2 zbLM^DbB3|T8mk&j;3;Z-)_36=o?r#P@e9jn;3{^O1#=utwDG0~)U6Icd&u~KJJ?zj zsMZ0AAKVRf39S@B@p#{P$-+>thd{l+b)3WwY{N0pr+nE3)x?RSP`mMJ0MsCDz!m%q z{GU4Dl|jKNd<*;!^MXuc4olW1a8{^`f%hMdWC1xWD)(WDniZ-Mc<-h)P2o!lm^@Ht z1K)=D$6-$y*cjHm$CXdwt*HMm6cLM`dN)6cO#3_LHn zGimxo9;o>~Ky7@+fjDq3SeQ)#Qv?b&;UI2ER`4P=61Dbtaxw!@5vW+FyPz%;9fI-1 z_KZMfK-~UI$O zIG&sjCRaxYHI2VP+)TW1Nb($O;hv~0*DKNYN>=!SP9KVOMz+H>&**m@UJ-QaP<1>T zG1LX@>je|)9PZ<-pQwhIEWvC{)CQnoiGFB=256G)SW;?dz QcmMzZ07*qoM6N<$f~rRacmMzZ literal 0 HcmV?d00001 diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_unknown_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_cloud_unknown_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c7be5df38e841e33803b40d549ce45a0020cf3 GIT binary patch literal 608 zcmV-m0-ybfP)}Am69(Z9t zo?-qo`|kS=J@wSn|EDu}ia9LcBOc)tDlOi9xQ$QvnT?smRrGfYvI*l@E{NyYmH97W zzQ8++k+LvVOmu+BV+Pl-6yaUKi84SJBVo$K9Jb{X^+mw+;W4(BSxJO8qb}rDlxouL zP9E>`$*K`RM`Fpl&=5Alx(M??LXbs#!*`(!)Y}17a2Q90ycu3&h$TG4m{2C_Mdli& zrOTBm9E>HuAk>9aFcVf$ok!3}2=iK~^if(b^rKWTzp%Gu&H>!_w;z7MWm#Q3pAcpl zcUxdK2z95O_Xa#k40Nmo=v>pgN!)C@|5Cwc?3PA9Fev=$xlZDEc0G6`SaR>F7n9-6aJ@wSnztV3JF_tB!Is`rd0000jXpSW>p@7y9%ZKE(AnQSMjctr2 zl~_V&!sRrO6`!kKehVH2N1@8=vQ*N8c{~Q~IF%3DTIEt!2+>%Vv7ZHy1=1TdH$-EZ zYK}8Nx4nJ zFx~}W#_P`xw*UntOI#yLg7ec#$`gxH8OqDc^)mCai<1)zQuXqS(r3T3kpimL_jGX# z@#uVeWv{kdq6FKA`>$0adDJ}9xV?CcPQ)wBp3^y!9WcI literal 0 HcmV?d00001 diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_cloud_off_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_cloud_off_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..fa6dd8da2f6fdc073924afe255b8b862a86bfaab GIT binary patch literal 834 zcmV-I1HJr-P)4Q_K~!jg?bykW3}GC`@ef0YZEzs8R)2?q%W4kSdx5C{K* zH4_&nE@F!V;UHlm4ibNW1V<+%+z`toh@FFNgdx^LbtmPm?w;zd>gkd6le~SX_kDlw z^L^|0F4eTvR$Fbg)mC*Ca23TAZAV}|j^R39;48l1F|Oe#)?idK%!VqU7k^4-szHp! zKD;WmO;cWB4< z=wNI}oA5EE@w^~9@ji&RvXMaBrJwb@A#XHWz zkD$@kItI=YBJEl`67RGtsJyN5J4v2vVl0-4E_&hl^BWt>4X*^1-3^*AD^G~B7E9j8 zdX>(K-k@SZhJngz7DV_aw!r7$VVWCd8Z`srWDxH>^l1(N`9mxZVm(y)$vcJO$`c~o zYWv`F@G$EluB5ymCI>P4VMp-rjscGC29*cIilF}^m?3$PZO_YfpsWyQgT5Ea6=#Bq z?^vCe>p+b{tSI@4_gh!4oG!T=eHW$IP)Mhhcq^Gc|9Go*oxUsj#9M@MEr962jiB8x zRW6%5t3V89sRS|6zki+`s5LViB)<)Y3dBw9t!2KfX*eypJGB~OWE%5v6+~ZUmvB$= z-qZ?+A+1UaJL^AygRV*tS6k|+0mUJDMXCJXsVJKH|I&P0Z4H+G0(^b M07*qoM6N<$fM@Sp2&U5`@NTS77MX3T(rBvIGE$OOs6 zgcwR56U@lKz(7}&Qi`F3D@9#m;L*JlDJ}-rBV3PTu+G-*T<6@q&pFO6?XUi){aD}H z-}hg8t^eAG96562$dRKyjK?lq$6E~G6|Q1GW>?{k!xmgaKZ>P3ZsRZ(|0~fEHlwff z;7aimooFxPt`>||;}&sI^(54c0|_1;kJngI;_k$+6x?@M*+}u*Q;Lt`4fYD7l9u}k zOB*464!+iCpx)?3YrO`}W+Xm}UG<1>$M=j4JdF!#Noim`3Mn~_#$3#cPSP4!GIW!s zU_o?{*1*gL3#k=pRUg$2jKLZ#7q$zdH1`$i!x3D-i!{X1 z*e4W@ELNEx!aitR4W>=Q{fvYc@j+PWYQl89%uxI%EUQ)g2;9n0{4aFWDxR=A%u0L_ zrz+@b#ctdaM(B%BiH~AJ)Tm9^>SiVWvoQC{(T1BSvXtaQXLY;{7 zPefVB%E0A>22Pame&D1qQl4jM;Cw;@@g(QoQdCTDP7zlthLQX3)a@#0o=h>VRkng z+v*_?j~ze6U91znzM6#@LIQg#+#e}?WObLKOW531#AKWns$8??!Xu1L=X+>O#U5NS oxB~u*IM-+cIdbI4k>mfzZxFlK*=ZmZPyhe`07*qoM6N<$g6H{KHvj+t literal 0 HcmV?d00001 diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_cloud_off_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_cloud_off_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..79d9717f89b5d264a6b2c7a26ff9988a592e5a79 GIT binary patch literal 1228 zcmV;-1T*`IP)@~8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11W8FmK~#90?b}PJRaG3v@sD0_zA~t;1lgdcISeW&C<1$!MN}$e zK}7a|qDjLBfzE6Yy(1b3y)?*@1`*^yd(expq6Zm7*;R=iP&u&DJPp=8ayXs;xo4mK zI_mzye{|RW|JM55wf0*3fA*%Kp`oFnp`oFnp`oFnYG!0?KaS_I8L#HhJpmWvqN!Mf zlcr)E`|u0C!x#7f+weyY&C(f{jA`K?tju`*7?$H@?4Qb$CH}@6Sb<+FiA`W6L zW)?Hl;pu16bTg@JlUmZIF{hxh4o#6J{f?J#x3o-7kp?)930#2N@f>~&G`nLv<`py4 z;ki*hleXek9G5|JHg3X>K({mAluWLb8>DS_*ct zw_{a_`U7*l`b?UQR|4&pG|Lv2s6Q~v@t5I_0C^e1Yk_tPPnW12a+Ly(i=1dt=b3imF_lCY>nNup^W1Z#VojXmE9jo$I7-lcJgQ zlc^Q-YtUeEi5=^vPLnPRbX(F=3`?d9O6*iG>NII_a)&%+AZZ~)@Xs}y7yID77o3t&+{YbmP>YzajuN#4vlay!D(jaFG zSGF6CNtLyz;bV?YlTOC>LB74Z%CT1j4LfJj(X`wq@KKPbB^CGo$8<&eJyK2ONZ;Kq z5zn0V4&Jj+I7fe1+c7Eq=Dl1xg%(|P9E3b3^?PUX5U%Sdyiou9(UB6vn)FaVbJ|R| zK97{hYSIQ7HlsPx3rKYjvMQ6-XECRfrTA(D23n>`xp(K8(rdWyD)x1lQ8K9~SwDw@ zGjNquj$DG%rT;*d_nzzGfb`B}o=>@s3i5nga?H?}Gywe$lbdSn*GSQ8CT%tX-*b!- qohCKr1gw;nRbx&=LqkKuF~WagV&o@kjCvdZ0000o7Om-hid~U;jA?S8&AGQgiwqgj+;;%OS&f+ye z#9A;U{O8&gCTn|fWfR{wW1^tnzp)diM~t;&*5NC~#c9|awr6~A$9x3eU*Lksaks^} z!o1RL088z`Mc>;Z`<=kX5;SPaO1u|2h=x6dBPIC#8fTUvMjnrs5I`?%tPC--oP$3q z2riag6JL_!d9DUQc4ME!m*g0$_4nv$*k#$k2D;Y<+=x|?d{xP<*$1%%+7!u8)!dYQ z5KEwoBl)SCi)1v3A0A<)LUdL7;ZxoG{*es+8K6Ct@=NBP`P<8OFYyuBqO-xY;!rUwV>AY7q zk7ty07`;RoEma3u)W&gbbX6AFjF}n)S=9E5JjX2M7X35n=Go^;m}?rW$5ai1ENTaY zjAkjU7V@-J2U*nSG*9wJVMh&u?8Y8#GtRT|06xIa!WQLsVL^HtSL8Js(%+xfcfv*F za@>Q%ZTNc$r!H;yL=A%M#_n!IoclWT`6f;v92LH=L6Ajl949R!&PHL5>eTmE7_C8& z-Pn`Mh(kCc<+VM8_cfnhcEe*e2(lX+T}GTnAw#y^q+?rx4NZJc52(>)egS5LYLHe8 z(9%-^#$AgDU=8el)F^FA{DV&?VaMYaEEmH>%FB9TZW5{X12k?0No0ztmrH`>%CtN;K207*qoM6N<$f~HpqaR2}S literal 0 HcmV?d00001 diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_cloud_off_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_cloud_off_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..93003e9a018e8d733ba85c33effe0ffa25768840 GIT binary patch literal 1619 zcmV-Z2CVssP)k8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11<*-EK~#90?VMYPRaF?rf5(|gt(n4Uv@yz{A}8odXg4OvkVtZT z$&#QKXH=>wBeTmx7iglOo9Vpt(o8>j&T4-fR8$`tQqHYkzBj$K&yMJRXn7V*#3^A>#sBQcp(wcA^FajJSd80>}u>)9~LZ36N=KqZ!#M{I- z;YwgzNO^h0m%yU97wrm-?)>_Q^CWCS?#`kbzc#i3-3i*jDsQ2?IIRhbfC*)pdBoqq zibO48i3-hULKPSWrYC3*D^!3D=q^nAP3T3slQvD*jr71uK^zm(J_*NxkAN3|WyrYW z0$>KvhKvV#fTh6Gz)q5zxd-Tq-yC+R0B@3?37-P@B7?EG%m9`HA7bt_)W^5Lxe4mD z#v5d7!mYp!8S1+lcweb8h+W9jRT^F=TNCo&4q#NFF^COzWG3e|+&7^Ecvqn@h~;)< zCg&w|7nWqioF!|~eH#uTAN*4BD(*iC0Bg{h@SZJ!X&9m$Pr@@Hy6WQ=TLLw70`~wf zBYp56fIrZ`XKgfGKb#M|0*sTs(OoiO zu|nTgOWFWvLH;b|(eSRAu-%~TBrw~CuuGADta&!P3npBPxmUENXi-a$IrE|#-?j-m z4Z1!lQq29N`zf9_Y;;lYGiaJbCi-%xpZK$g&G015L{eO$H1*~!VhQo@{Bfi|Jpe2~ zK2}k)i4~-AT{PiigPvcIY3_}{1Him2E595`X3{qNK42ws=fuTT6SSk_+V~E5l$8Gw z+JJAA6;1%_fYvk>;-(3GNV`xu9?uI)M9!~#YzIZ5Z$Y1 z5BUs6Tr#0cslyagz>B~%O{JQDyQAbg5_H9c=}HaS*oxuzW+&z>f(f#H?S$cq30WFY zMW#7IpM*yg1+2^V`XX_`gscsyBEM`KVw&gKNBZ7QTwE}r5$6E&fjg0Lz;8;8K`g5; zup9G;cV&(j6osoM)Y5{q&+kf|eO8^?lNfF z3+9BRg$0X_i_0d=H|RM8vh*kFpj8D5PKv80bQrXp0P{MpvSbFkXu?c`j!7`5VI0Qp zR74zHGhv=V!$FY62d2rm{+xwoiAyFdHPpX1IM6g5JxaM2thr)>Y4PIb;J}9!Lf7Xc zGB0eK&U}aexD#_W*d%aM#v=2^rU|PQbzWb4f@YcN7;sUBB8$L=30;`){{8hQ z%|*Ao|9iX%QM3RbDC&8>(aBFJMULTLM~!F!-cgi)jF9x6HYCSUBXSaW4*5x47VL`x3$ldgMqmzS)>O7; z)2S)oZmq}x+*qLDLS$vaQ242h>BruNdagxU6E-6s>Dcs<|I*a5L{byBkTSFIGGrGi z+YR7C#4+J0^4d|Qr<-U69w*-NrDhGS33C+3#HJhBj>h&5hqlA^1|!S@9zwPOK2v*3 zsZGer!P&s=$n-=Hvb8}MGT?A^ERYq$$m+@e87n3BK_Qrq%@C_?D<3AKXFPLOdRi$K&yMJRVQ^_y^WC#r)E` R>#YC)002ovPDHLkV1ig-`Pl#f literal 0 HcmV?d00001 diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_cloud_unknown_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_cloud_unknown_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f9196f6f2a72e5a56d95004786249c0944e14494 GIT binary patch literal 1489 zcmV;?1upuDP)8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11x`ssK~#90?VN3h6;&9=fA@MzD`|set8H7iQqe6ch>9o>!ghtU zu>4R&^db9DL=jX_2nAsjSri3n(1++l5(Q;%_VPiqG)oa8Kdkmbnt__S?Y7$Lw!3|J z?q%;@X70S5GiPS*^MgOTJ9FneXa8sJnK|b?GoUDnq9}@@D2k#eilQirq9{tyDY>pd z1M`4oz#?EFa4|5ey6+Hh5EuY<0N+%9P8x`NZZ+;=pcj}A%&zVmtc&|2uo>6}j2VcV z8I}TDfC^it5LgFX6*F#T=mowd+CT55G2kuWf{<}Lf%OLB zP6D3-m&f_%U2{J$iWw7X8U`K+h`R(hYB=sG;5p#5xMrkD33v^&1~lqj;7pI$4+8&L zjJpjuKbbxDS%+QoYuW;|)x~{?=+~Gy`USap$Rw*s$Nc(6mkSrg`&;APyK;X-4;6$boEL=SSC=GqKb+K}ABWW0)d z6I^P7Cf|Y?5sZw(8Nl02&F8ctC1k2&ql@5o;r*-8J%U8%g+n#z_ngG zY&XDS%jM^Z8@)E#Y=CZLo?Q{H^x9~%0eUT#oktdUZM4|{T^7sEBc5v&HXGn5#~S>4bTD1Mf$kf zU}G4cuUvr`13pGZ`Wun?u2d)iHvnsaJ-8obrmYjmlIonKMn3NrS+O#4g5UCFavd@}!+OT4XN)FGj3v(eyb}DT=An>I*3!0H-H*F(yxj zs9=$`35SbFH{&LKBrE!v=?Pt_(t)I6yEegUv*g^R01xB-EOe=x0t~IEj4Uns zm34sW3sG|dVjnM4fJZG8a0+>@D=eKzmYW}+A#1@k4kI@=zVR!_Afi>-iChfBG7db^ zWdDx3-)8_X(LD3yH-JBJ-wn9Zn@!A#O9{9IY22XrPXqj$0V7=L@pvBlG7lM3go*t- z&{n~If^L>MXt1nvfUkgyLVWgDBy)VIOp56g8Dzv@S&tBG{s^!dNz@&vZ5+UTSKvxZ z0t}17Pfg-XAlI9Y#)Hbp*P&H0wdz$ulGFTH1>A>BO;4i?Y&TSiJYs6WeKztuoEM|O zD}D!7kPF8%hANUbOg%ty5_r#N-%;dF)0Yx5AaLCuyU^>+j7ft^wIXjIQ_`)*LPO=W z(|jp+ACju>OB=F&>H3UJTO*ixp+-;|PoLj`wL#brvLM}RoQ14~JEMLSyq0J)gGFJv z%i#45FpfOge#}u_TyX~uU*Fj{53~=sm4Mr(g3&{hKH4^36LDLC+lV$#o_8K|71(bk z^b6#yIFw>tT+)ZU#5Hw-`o1nC^J`HGb#cvh;Cke?F)E!@Q%ro=LxQJ9%g8Gq2XTMj zZd)tknv@3ZNb;`fx6Wos!${U!rkMrYjl7f7wP7~&1O79cnWGE12N}eLS%l7uYKc{f rq9}@@D2k#eilQirq9}@@D2e$WAv!?Zh9JZ;00000NkvXXu0mjfGm4|# literal 0 HcmV?d00001 diff --git a/OpenKeychain/src/main/res/layout/key_keyserver_card_content.xml b/OpenKeychain/src/main/res/layout/key_keyserver_card_content.xml new file mode 100644 index 000000000..bf0636d50 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/key_keyserver_card_content.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 31a81e651..8b075b06e 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1842,6 +1842,11 @@ "Healthy (Partially Stripped)" "Click for details" + "Published" + "Not Published" + "Unknown" + "Last updated: %s" + "This key uses the %1$s algorithm with a strength of %2$s bits. A secure key should have a strength of 2048 bits." "This key can\'t be upgraded. For secure communication, the owner must generate a new key." diff --git a/graphics/drawables/ic_cloud_off.svg b/graphics/drawables/ic_cloud_off.svg new file mode 100644 index 000000000..b2373ff16 --- /dev/null +++ b/graphics/drawables/ic_cloud_off.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/graphics/drawables/ic_cloud_unknown.svg b/graphics/drawables/ic_cloud_unknown.svg new file mode 100644 index 000000000..8fda8d19f --- /dev/null +++ b/graphics/drawables/ic_cloud_unknown.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/graphics/update-drawables.sh b/graphics/update-drawables.sh index 4407315b7..f4c998e4b 100755 --- a/graphics/update-drawables.sh +++ b/graphics/update-drawables.sh @@ -22,7 +22,7 @@ SRC_DIR=./drawables/ #inkscape -w 512 -h 512 -e "$PLAY_DIR/$NAME.png" $NAME.svg -for NAME in "broken_heart" "ic_cloud_search" "ic_action_encrypt_file" "ic_action_encrypt_text" "ic_action_verified_cutout" "ic_action_encrypt_copy" "ic_action_encrypt_paste" "ic_action_encrypt_save" "ic_action_encrypt_share" "status_lock_closed" "status_lock_error" "status_lock_open" "status_signature_expired_cutout" "status_signature_invalid_cutout" "status_signature_revoked_cutout" "status_signature_unknown_cutout" "status_signature_unverified_cutout" "status_signature_verified_cutout" "key_flag_authenticate" "key_flag_certify" "key_flag_encrypt" "key_flag_sign" "yubi_icon" "ic_stat_notify" "status_signature_verified_inner" "link" "octo_link" +for NAME in "ic_cloud_unknown" "ic_cloud_off" "broken_heart" "ic_cloud_search" "ic_action_encrypt_file" "ic_action_encrypt_text" "ic_action_verified_cutout" "ic_action_encrypt_copy" "ic_action_encrypt_paste" "ic_action_encrypt_save" "ic_action_encrypt_share" "status_lock_closed" "status_lock_error" "status_lock_open" "status_signature_expired_cutout" "status_signature_invalid_cutout" "status_signature_revoked_cutout" "status_signature_unknown_cutout" "status_signature_unverified_cutout" "status_signature_verified_cutout" "key_flag_authenticate" "key_flag_certify" "key_flag_encrypt" "key_flag_sign" "yubi_icon" "ic_stat_notify" "status_signature_verified_inner" "link" "octo_link" do echo $NAME inkscape -w 24 -h 24 -e "$MDPI_DIR/${NAME}_24dp.png" "$SRC_DIR/$NAME.svg"