fixed several issues, recyclerview now used in DisplayLogFragment, cosmetic changes

This commit is contained in:
Tobias Erthal 2016-09-12 15:31:47 +02:00
parent 8dcf6ee08a
commit bef769e22a
No known key found for this signature in database
GPG key ID: 48EB86BE1239F546
11 changed files with 374 additions and 175 deletions

View file

@ -140,10 +140,6 @@ public class KeyListFragment extends RecyclerFragment<KeySectionedListAdapter>
case R.id.menu_key_list_multi_delete: {
long[] keyIds = getAdapter().getSelectedMasterKeyIds();
boolean hasSecret = getAdapter().isAnySecretKeySelected();
System.out.println(Arrays.toString(keyIds));
System.out.println(hasSecret);
Intent intent = new Intent(getActivity(), DeleteKeyDialogActivity.class);
intent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, keyIds);
intent.putExtra(DeleteKeyDialogActivity.EXTRA_HAS_SECRET, hasSecret);

View file

@ -38,37 +38,35 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.tonicartos.superslim.LayoutManager;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogLevel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.SubLogEntryParcel;
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.ui.adapter.NestedLogAdapter;
import org.sufficientlysecure.keychain.ui.dialog.ShareLogDialogFragment;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerFragment;
import java.io.IOException;
import java.io.OutputStream;
public class LogDisplayFragment extends ListFragment implements OnItemClickListener {
LogAdapter mAdapter;
OperationResult mResult;
public class LogDisplayFragment extends RecyclerFragment<NestedLogAdapter>
implements NestedLogAdapter.LogActionListener {
private OperationResult mResult;
public static final String EXTRA_RESULT = "log";
protected int mTextColor;
private Uri mLogTempFile;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextColor = FormattingUtils.getColorFromAttr(getActivity(), R.attr.colorText);
setHasOptionsMenu(true);
}
@ -93,14 +91,11 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
return;
}
mAdapter = new LogAdapter(getActivity(), mResult.getLog());
setListAdapter(mAdapter);
getListView().setOnItemClickListener(this);
getListView().setFastScrollEnabled(true);
getListView().setDividerHeight(0);
NestedLogAdapter adapter = new NestedLogAdapter(getContext(), mResult.getLog());
adapter.setListener(this);
setAdapter(adapter);
setLayoutManager(new LayoutManager(getContext()));
}
@Override
@ -130,7 +125,6 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
}
private void shareLog() {
Activity activity = getActivity();
if (activity == null) {
return;
@ -144,7 +138,7 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
try {
OutputStream outputStream = activity.getContentResolver().openOutputStream(mLogTempFile);
outputStream.write(log.getBytes());
} catch (IOException e) {
} catch (IOException | NullPointerException e) {
Notify.create(activity, R.string.error_log_share_internal, Style.ERROR).show();
return;
}
@ -153,129 +147,12 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
ShareLogDialogFragment shareLogDialog = ShareLogDialogFragment.newInstance(mLogTempFile);
shareLogDialog.show(getActivity().getSupportFragmentManager(), "shareLogDialog");
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
LogEntryParcel parcel = mAdapter.getItem(position);
if ( ! (parcel instanceof SubLogEntryParcel)) {
return;
}
Intent intent = new Intent(
getActivity(), LogDisplayActivity.class);
intent.putExtra(LogDisplayFragment.EXTRA_RESULT, ((SubLogEntryParcel) parcel).getSubResult());
public void onSubEntryClicked(SubLogEntryParcel subLogEntryParcel) {
Intent intent = new Intent(getActivity(), LogDisplayActivity.class);
intent.putExtra(LogDisplayFragment.EXTRA_RESULT, subLogEntryParcel.getSubResult());
startActivity(intent);
}
private class LogAdapter extends ArrayAdapter<LogEntryParcel> {
private LayoutInflater mInflater;
private int dipFactor;
public LogAdapter(Context context, OperationResult.OperationLog log) {
super(context, R.layout.log_display_item, log.toList());
mInflater = LayoutInflater.from(getContext());
dipFactor = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) 8, getResources().getDisplayMetrics());
}
private class ItemHolder {
final View mSecond;
final TextView mText, mSecondText;
final ImageView mImg, mSecondImg, mSub;
public ItemHolder(TextView text, ImageView image, ImageView sub, View second, TextView secondText, ImageView secondImg) {
mText = text;
mImg = image;
mSub = sub;
mSecond = second;
mSecondText = secondText;
mSecondImg = secondImg;
}
}
// Check if convertView.setPadding is redundant
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LogEntryParcel entry = getItem(position);
ItemHolder ih;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.log_display_item, parent, false);
ih = new ItemHolder(
(TextView) convertView.findViewById(R.id.log_text),
(ImageView) convertView.findViewById(R.id.log_img),
(ImageView) convertView.findViewById(R.id.log_sub),
convertView.findViewById(R.id.log_second),
(TextView) convertView.findViewById(R.id.log_second_text),
(ImageView) convertView.findViewById(R.id.log_second_img)
);
convertView.setTag(ih);
} else {
ih = (ItemHolder) convertView.getTag();
}
if (entry instanceof SubLogEntryParcel) {
ih.mSub.setVisibility(View.VISIBLE);
convertView.setClickable(false);
convertView.setPadding((entry.mIndent) * dipFactor, 0, 0, 0);
OperationResult result = ((SubLogEntryParcel) entry).getSubResult();
LogEntryParcel subEntry = result.getLog().getLast();
if (subEntry != null) {
ih.mSecond.setVisibility(View.VISIBLE);
// special case: first parameter may be a quantity
if (subEntry.mParameters != null && subEntry.mParameters.length > 0
&& subEntry.mParameters[0] instanceof Integer) {
ih.mSecondText.setText(getResources().getQuantityString(subEntry.mType.getMsgId(),
(Integer) subEntry.mParameters[0],
subEntry.mParameters));
} else {
ih.mSecondText.setText(getResources().getString(subEntry.mType.getMsgId(),
subEntry.mParameters));
}
ih.mSecondText.setTextColor(subEntry.mType.mLevel == LogLevel.DEBUG ? Color.GRAY : mTextColor);
switch (subEntry.mType.mLevel) {
case DEBUG: ih.mSecondImg.setBackgroundColor(Color.GRAY); break;
case INFO: ih.mSecondImg.setBackgroundColor(mTextColor); break;
case WARN: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_orange_light)); break;
case ERROR: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
case START: ih.mSecondImg.setBackgroundColor(mTextColor); break;
case OK: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_green_light)); break;
case CANCELLED: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
}
} else {
ih.mSecond.setVisibility(View.GONE);
}
} else {
ih.mSub.setVisibility(View.GONE);
ih.mSecond.setVisibility(View.GONE);
convertView.setClickable(true);
}
// special case: first parameter may be a quantity
if (entry.mParameters != null && entry.mParameters.length > 0
&& entry.mParameters[0] instanceof Integer) {
ih.mText.setText(getResources().getQuantityString(entry.mType.getMsgId(),
(Integer) entry.mParameters[0],
entry.mParameters));
} else {
ih.mText.setText(getResources().getString(entry.mType.getMsgId(),
entry.mParameters));
}
convertView.setPadding((entry.mIndent) * dipFactor, 0, 0, 0);
ih.mText.setTextColor(entry.mType.mLevel == LogLevel.DEBUG ? Color.GRAY : mTextColor);
switch (entry.mType.mLevel) {
case DEBUG: ih.mImg.setBackgroundColor(Color.GRAY); break;
case INFO: ih.mImg.setBackgroundColor(mTextColor); break;
case WARN: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_orange_light)); break;
case ERROR: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
case START: ih.mImg.setBackgroundColor(mTextColor); break;
case OK: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_green_light)); break;
case CANCELLED: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break;
}
return convertView;
}
}
}

View file

@ -190,7 +190,7 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
@Override
protected short getSectionItemViewType(int position) {
if(moveCursor(position)) {
if (moveCursor(position)) {
KeyCursor c = getCursor();
if (c.isSecret() && c.getKeyId() == 0L) {
@ -435,24 +435,24 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
int pos = getAdapterPosition();
switch (v.getId()) {
case R.id.key_list_item_slinger_button:
if(mListener != null) {
if (mListener != null) {
mListener.onSlingerButtonClicked(getItemId());
}
break;
default:
if(getSelectedCount() == 0) {
if(mListener != null) {
if (getSelectedCount() == 0) {
if (mListener != null) {
mListener.onKeyItemClicked(getItemId());
}
} else {
if(isSelected(pos)) {
if (isSelected(pos)) {
deselectPosition(pos);
} else {
selectPosition(pos);
}
if(mListener != null) {
if (mListener != null) {
mListener.onSelectionStateChanged(getSelectedCount());
}
}
@ -464,10 +464,10 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
@Override
public boolean onLongClick(View v) {
System.out.println("Long Click!");
if(getSelectedCount() == 0) {
if (getSelectedCount() == 0) {
selectPosition(getAdapterPosition());
if(mListener != null) {
if (mListener != null) {
mListener.onSelectionStateChanged(getSelectedCount());
}
return true;

View file

@ -0,0 +1,266 @@
package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context;
import android.graphics.Color;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Pair;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.tonicartos.superslim.LayoutManager;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import java.util.ArrayList;
import java.util.List;
public class NestedLogAdapter extends RecyclerView.Adapter<NestedLogAdapter.LogEntryViewHolder> {
private static final int ENTRY_TYPE_REGULAR = 0;
private static final int ENTRY_TYPE_SUBLOG = 1;
private final int mIndentFactor;
private LogActionListener mListener;
private List<Pair<OperationResult.LogEntryParcel, Integer>> mLogEntries;
public NestedLogAdapter(Context context) {
super();
mIndentFactor = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) 8, context.getResources().getDisplayMetrics());
}
public NestedLogAdapter(Context context, OperationResult.OperationLog log) {
this(context);
setLog(log);
}
public void setListener(LogActionListener listener) {
mListener = listener;
}
public void setLog(OperationResult.OperationLog log) {
List<OperationResult.LogEntryParcel> list = log.toList();
if (mLogEntries != null) {
mLogEntries.clear();
} else {
mLogEntries = new ArrayList<>(list.size());
}
int lastSection = 0;
for (int i = 0; i < list.size(); i++) {
OperationResult.LogEntryParcel parcel = list.get(i);
if(parcel.mIndent < 1) {
lastSection = i;
}
mLogEntries.add(new Pair<>(parcel, lastSection));
}
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return mLogEntries != null ? mLogEntries.size() : 0;
}
@Override
public long getItemId(int position) {
OperationResult.LogEntryParcel parcel = getItem(position);
return parcel != null ? parcel.hashCode() : -1L;
}
public OperationResult.LogEntryParcel getItem(int position) {
return mLogEntries != null ?
mLogEntries.get(position).first : null;
}
public int getFirstSectionPosition(int position) {
return mLogEntries != null ?
mLogEntries.get(position).second : 0;
}
@Override
public int getItemViewType(int position) {
return (getItem(position) instanceof OperationResult.SubLogEntryParcel) ?
ENTRY_TYPE_SUBLOG : ENTRY_TYPE_REGULAR;
}
public boolean isSection(int position) {
return mLogEntries != null && mLogEntries.get(position).second == position;
}
@Override
public LogEntryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ENTRY_TYPE_SUBLOG:
return new SublogEntryViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.log_display_sublog_item, parent, false));
case ENTRY_TYPE_REGULAR:
return new LogEntryViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.log_display_regular_item, parent, false));
default:
return null;
}
}
@Override
public void onBindViewHolder(LogEntryViewHolder holder, int position) {
LayoutManager.LayoutParams layoutParams = LayoutManager.LayoutParams
.from(holder.itemView.getLayoutParams());
layoutParams.isHeader = isSection(position);
layoutParams.setFirstPosition(getFirstSectionPosition(position));
holder.bind(getItem(position), mIndentFactor);
holder.itemView.setLayoutParams(layoutParams);
}
class LogEntryViewHolder extends RecyclerView.ViewHolder {
private TextView mLogText;
private ImageView mLogImg;
public LogEntryViewHolder(View itemView) {
super(itemView);
mLogText = (TextView) itemView.findViewById(R.id.log_text);
mLogImg = (ImageView) itemView.findViewById(R.id.log_img);
}
public void bind(OperationResult.LogEntryParcel entry, int indentFactor) {
String logText;
if (entry.mParameters != null
&& entry.mParameters.length > 0
&& entry.mParameters[0] instanceof Integer) {
logText = itemView.getResources().getQuantityString(entry.mType.getMsgId(),
(int) entry.mParameters[0], entry.mParameters);
} else {
logText = itemView.getResources().getString(entry.mType.getMsgId(),
entry.mParameters);
}
int textColor, indicatorColor;
textColor = indicatorColor = FormattingUtils.getColorFromAttr(
itemView.getContext(), R.attr.colorText);
switch (entry.mType.mLevel) {
case DEBUG:
textColor = Color.GRAY;
indicatorColor = Color.GRAY;
break;
case WARN:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_orange_light);
break;
case ERROR:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_red_light);
break;
case OK:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_green_light);
break;
case CANCELLED:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_red_light);
break;
}
mLogText.setText(logText);
mLogText.setTextColor(textColor);
mLogImg.setBackgroundColor(indicatorColor);
itemView.setPadding((entry.mIndent) * indentFactor, 0, 0, 0);
}
}
class SublogEntryViewHolder extends LogEntryViewHolder implements View.OnClickListener {
private TextView mSublogText;
private ImageView mSublogImg;
public SublogEntryViewHolder(View itemView) {
super(itemView);
itemView.setClickable(true);
itemView.setOnClickListener(this);
mSublogText = (TextView) itemView.findViewById(R.id.log_second_text);
mSublogImg = (ImageView) itemView.findViewById(R.id.log_second_img);
}
@Override
public void bind(OperationResult.LogEntryParcel entry, int indentFactor) {
super.bind(entry, indentFactor);
OperationResult.LogEntryParcel sublogEntry = ((OperationResult.SubLogEntryParcel) entry)
.getSubResult().getLog().getLast();
String logText;
if (sublogEntry.mParameters != null
&& sublogEntry.mParameters.length > 0
&& sublogEntry.mParameters[0] instanceof Integer) {
logText = itemView.getResources().getQuantityString(sublogEntry.mType.getMsgId(),
(int) sublogEntry.mParameters[0], sublogEntry.mParameters);
} else {
logText = itemView.getResources().getString(sublogEntry.mType.getMsgId(),
sublogEntry.mParameters);
}
int textColor, indicatorColor;
textColor = indicatorColor = FormattingUtils.getColorFromAttr(
itemView.getContext(), R.attr.colorText);
switch (sublogEntry.mType.mLevel) {
case DEBUG:
textColor = Color.GRAY;
indicatorColor = Color.GRAY;
break;
case WARN:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_orange_light);
break;
case ERROR:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_red_light);
break;
case OK:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_green_light);
break;
case CANCELLED:
indicatorColor = ContextCompat.getColor(itemView.getContext(),
R.color.android_red_light);
break;
}
mSublogText.setText(logText);
mSublogText.setTextColor(textColor);
mSublogImg.setBackgroundColor(indicatorColor);
}
@Override
public void onClick(View v) {
if (mListener != null) {
OperationResult.LogEntryParcel parcel = getItem(getAdapterPosition());
if (parcel instanceof OperationResult.SubLogEntryParcel) {
mListener.onSubEntryClicked((OperationResult.SubLogEntryParcel) parcel);
}
}
}
}
public interface LogActionListener {
void onSubEntryClicked(OperationResult.SubLogEntryParcel subLogEntryParcel);
}
}

View file

@ -10,6 +10,8 @@ import android.view.ViewGroup;
import com.tonicartos.superslim.LayoutManager;
import org.sufficientlysecure.keychain.util.Log;
import java.util.Objects;
/**
* @param <T> section type.
* @param <VH> the view holder extending {@code BaseViewHolder<Cursor>} that is bound to the cursor data.
@ -71,7 +73,6 @@ public abstract class SectionCursorAdapter<C extends Cursor, T, VH extends Secti
moveCursor(-1);
try {
mSectionMap.clear();
appendSections(getCursor());
} catch (IllegalStateException e) {
Log.e(TAG, "Couldn't build sections. Perhaps you're moving the cursor" +
@ -87,10 +88,12 @@ public abstract class SectionCursorAdapter<C extends Cursor, T, VH extends Secti
int cursorPosition = 0;
while(hasValidData() && cursor.moveToNext()) {
T section = getSectionFromCursor(cursor);
if (cursor.getPosition() != cursorPosition)
if (cursor.getPosition() != cursorPosition) {
throw new IllegalStateException("Do not move the cursor's position in getSectionFromCursor.");
if (!hasSection(section))
}
if (!hasSection(section)) {
mSectionMap.append(cursorPosition + mSectionMap.size(), section);
}
cursorPosition++;
}
}
@ -119,11 +122,13 @@ public abstract class SectionCursorAdapter<C extends Cursor, T, VH extends Secti
@Override
public final long getItemId(int listPosition) {
if (isSection(listPosition))
return -1;
else {
int index = mSectionMap.indexOfKey(listPosition);
if (index < 0) {
int cursorPosition = getCursorPositionWithoutSections(listPosition);
return super.getItemId(cursorPosition);
} else {
T section = mSectionMap.valueAt(index);
return section != null ? section.hashCode() : 0L;
}
}

View file

@ -41,7 +41,6 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.util.Log;
public class RecyclerFragment<A extends RecyclerView.Adapter> extends Fragment {
private static final int INTERNAL_LIST_VIEW_ID = android.R.id.list;
private static final int INTERNAL_EMPTY_VIEW_ID = android.R.id.empty;
private static final int INTERNAL_LIST_CONTAINER_ID = android.R.id.widget_frame;
@ -104,7 +103,7 @@ public class RecyclerFragment<A extends RecyclerView.Adapter> extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
final Context context = parent.getContext();
final Context context = getContext();
FrameLayout root = new FrameLayout(context);
LinearLayout progressContainer = new LinearLayout(context);

View file

@ -40,9 +40,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingStart="16dp"
android:paddingRight="32dp"
android:paddingEnd="32dp"
android:paddingBottom="72dp"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay" />
android:scrollbars="vertical"
android:scrollbarStyle="outsideOverlay"/>
<LinearLayout
android:id="@android:id/empty"

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:super="http://schemas.android.com/apk/lib-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:colorBackground"
super:slm_headerDisplay="sticky|inline"
super:slm_section_sectionManager="linear"
tools:ignore="ResAuto">
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/log_img"
android:minWidth="10dp"
android:background="?attr/colorLogBackground" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/log_text"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
tools:text="Log Entry Text" />
</LinearLayout>

View file

@ -1,9 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:super="http://schemas.android.com/apk/lib-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
super:slm_headerDisplay="sticky|inline"
super:slm_section_sectionManager="linear"
tools:ignore="ResAuto">
<LinearLayout
android:orientation="horizontal"
@ -20,13 +29,13 @@
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Log Entry Text"
android:id="@+id/log_text"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"/>
android:layout_gravity="center_vertical"
tools:text="Log Entry Text" />
<ImageView
android:layout_width="wrap_content"
@ -58,13 +67,13 @@
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Log Entry Text"
android:id="@+id/log_second_text"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"/>
android:layout_gravity="center_vertical"
tools:text="Log Entry Text" />
</LinearLayout>
</LinearLayout>

View file

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
@ -9,7 +12,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|left"
android:text="header text" />
tools:text="header text" />
<!--
<TextView

View file

@ -1,46 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:singleLine="true"
android:maxLines="1"
android:descendantFocusability="blocksDescendants"
android:background="?attr/selectableItemBackground"
android:focusable="false">
<TextView
android:id="@+id/signerName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="signer name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
android:layout_alignParentStart="true"
tools:text="signer name" />
<TextView
android:id="@+id/signerKeyId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="&lt;user@example.com>"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_below="@+id/signerName"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
android:layout_alignParentStart="true"
tools:text="&lt;user@example.com>" />
<TextView
android:id="@+id/signStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="status"
android:visibility="visible"
android:layout_above="@+id/signerKeyId"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="10dp" />
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
tools:text="status" />
</RelativeLayout>