UI improvements and fixes for older Android versions

This commit is contained in:
Christian Basler 2017-07-10 06:21:29 +02:00
parent 1c284eba26
commit 433c757107
27 changed files with 352 additions and 192 deletions

View File

@ -1,5 +1,5 @@
apply plugin: 'idea'
apply plugin: 'com.android.application'
apply plugin: 'idea'
ext {
appName = "Abit"
@ -44,6 +44,7 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:appcompat-v7:$supportVersion"
compile "com.android.support:preference-v7:$supportVersion"
compile "com.android.support:support-v4:$supportVersion"
compile "com.android.support:design:$supportVersion"
compile "com.android.support:multidex:1.0.1"

View File

@ -84,16 +84,6 @@
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".SettingsActivity"
android:label="@string/settings"
android:parentActivityName=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".CreateAddressActivity"
android:label="@string/title_activity_open_bitmessage_link"
@ -182,10 +172,10 @@
<activity
android:name=".StatusActivity"
android:label="@string/title_activity_status"
android:parentActivityName=".SettingsActivity">
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".SettingsActivity"/>
android:value=".MainActivity"/>
</activity>
</application>

View File

@ -27,7 +27,7 @@ import ch.dissem.apps.abit.listener.ListSelectionListener;
/**
* @author Christian Basler
*/
public abstract class AbstractItemListFragment<T> extends ListFragment implements ListHolder {
public abstract class AbstractItemListFragment<L, T> extends ListFragment implements ListHolder<L> {
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
@ -143,4 +143,14 @@ public abstract class AbstractItemListFragment<T> extends ListFragment implement
activatedPosition = position;
}
@Override
public L getCurrentLabel() {
return null;
}
@Override
public boolean showPreviousList() {
return false;
}
}

View File

@ -47,7 +47,7 @@ import io.github.yavski.fabspeeddial.SimpleMenuListenerAdapter;
/**
* Fragment that shows a list of all contacts, the ones we subscribed to first.
*/
public class AddressListFragment extends AbstractItemListFragment<BitmessageAddress> {
public class AddressListFragment extends AbstractItemListFragment<Void, BitmessageAddress> {
private ArrayAdapter<BitmessageAddress> adapter;
@Override
@ -166,7 +166,7 @@ public class AddressListFragment extends AbstractItemListFragment<BitmessageAddr
}
@Override
public void updateList(Label label) {
public void updateList(Void label) {
updateList();
}

View File

@ -16,13 +16,15 @@
package ch.dissem.apps.abit;
import ch.dissem.bitmessage.entity.valueobject.Label;
/**
* @author Christian Basler
*/
public interface ListHolder {
void updateList(Label label);
public interface ListHolder<L> {
void updateList(L label);
void setActivateOnItemClick(boolean activateOnItemClick);
L getCurrentLabel();
boolean showPreviousList();
}

View File

@ -21,6 +21,7 @@ import android.graphics.Point;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
@ -195,11 +196,15 @@ public class MainActivity extends AppCompatActivity
}
private <F extends Fragment & ListHolder> void changeList(F listFragment) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.item_list, listFragment)
.addToBackStack(null)
.commit();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.item_list, listFragment);
Fragment detailFragment = getSupportFragmentManager().findFragmentById(R.id.message_detail_container);
if (detailFragment != null) {
transaction.remove(detailFragment);
}
transaction.addToBackStack(null).commit();
if (twoPane) {
// In two-pane mode, list items should be given the
@ -325,15 +330,31 @@ public class MainActivity extends AppCompatActivity
}.execute();
}
@Override
public void onBackPressed() {
Fragment listFragment = getSupportFragmentManager().findFragmentById(R.id.item_list);
if (listFragment instanceof ListHolder) {
ListHolder listHolder = (ListHolder) listFragment;
if (listHolder.showPreviousList()) {
IDrawerItem drawerItem = drawer.getDrawerItem(listHolder.getCurrentLabel());
if (drawerItem != null){
drawer.setSelection(drawerItem);
}
return;
}
}
super.onBackPressed();
}
private class DrawerItemClickListener implements Drawer.OnDrawerItemClickListener {
@Override
public boolean onItemClick(View view, int position, IDrawerItem item) {
Fragment itemList = getSupportFragmentManager().findFragmentById(R.id.item_list);
if (item.getTag() instanceof Label) {
selectedLabel = (Label) item.getTag();
if (getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof
if (itemList instanceof
MessageListFragment) {
((MessageListFragment) getSupportFragmentManager()
.findFragmentById(R.id.item_list)).updateList(selectedLabel);
((MessageListFragment) itemList).updateList(selectedLabel);
} else {
MessageListFragment listFragment = new MessageListFragment();
changeList(listFragment);
@ -344,17 +365,18 @@ public class MainActivity extends AppCompatActivity
Nameable<?> ni = (Nameable<?>) item;
switch (ni.getName().getTextRes()) {
case R.string.contacts_and_subscriptions:
if (!(getSupportFragmentManager().findFragmentById(R.id
.item_list) instanceof AddressListFragment)) {
if (!(itemList instanceof AddressListFragment)) {
changeList(new AddressListFragment());
} else {
((AddressListFragment) getSupportFragmentManager()
.findFragmentById(R.id.item_list)).updateList();
((AddressListFragment) itemList).updateList();
}
return false;
case R.string.settings:
startActivity(new Intent(MainActivity.this, SettingsActivity
.class));
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.item_list, new SettingsFragment())
.addToBackStack(null)
.commit();
return false;
case R.string.full_node:
return true;
@ -501,7 +523,7 @@ public class MainActivity extends AppCompatActivity
Fragment fragment;
if (item instanceof Plaintext) {
fragment = new MessageDetailFragment();
} else if (item instanceof String) {
} else if (item instanceof BitmessageAddress) {
fragment = new AddressDetailFragment();
} else {
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but was " + item.getClass().getSimpleName());
@ -517,7 +539,7 @@ public class MainActivity extends AppCompatActivity
if (item instanceof Plaintext) {
detailIntent = new Intent(this, MessageDetailActivity.class);
detailIntent.putExtra(EXTRA_SHOW_LABEL, selectedLabel);
} else if (item instanceof String) {
} else if (item instanceof BitmessageAddress) {
detailIntent = new Intent(this, AddressDetailActivity.class);
} else {
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but " +
@ -529,6 +551,18 @@ public class MainActivity extends AppCompatActivity
}
}
public boolean hasDetailPane() {
return twoPane;
}
public void setDetailView(Fragment fragment) {
if (twoPane) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.message_detail_container, fragment)
.commit();
}
}
@Override
public void updateTitle(CharSequence title) {
if (getSupportActionBar() != null) {

View File

@ -38,10 +38,8 @@ import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeMana
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager;
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Stack;
import ch.dissem.apps.abit.adapter.SwipeableMessageAdapter;
import ch.dissem.apps.abit.listener.ActionBarListener;
@ -51,7 +49,6 @@ import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.ports.MessageRepository;
import io.github.yavski.fabspeeddial.FabSpeedDial;
import io.github.yavski.fabspeeddial.SimpleMenuListenerAdapter;
@ -68,7 +65,7 @@ import static ch.dissem.apps.abit.MessageDetailFragment.isInTrash;
* Activities containing this fragment MUST implement the {@link ListSelectionListener}
* interface.
*/
public class MessageListFragment extends Fragment implements ListHolder {
public class MessageListFragment extends Fragment implements ListHolder<Label> {
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
@ -82,6 +79,8 @@ public class MessageListFragment extends Fragment implements ListHolder {
private AndroidMessageRepository messageRepo;
private boolean activateOnItemClick;
private Stack<Label> backStack = new Stack<>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -95,11 +94,18 @@ public class MessageListFragment extends Fragment implements ListHolder {
MainActivity activity = (MainActivity) getActivity();
messageRepo = Singleton.getMessageRepository(activity);
doUpdateList(activity.getSelectedLabel());
if (backStack.isEmpty()) {
doUpdateList(activity.getSelectedLabel());
} else {
doUpdateList(backStack.peek());
}
}
@Override
public void updateList(Label label) {
if (currentLabel != null && !currentLabel.equals(label)) {
backStack.push(currentLabel);
}
if (!isResumed()) {
currentLabel = label;
return;
@ -330,4 +336,19 @@ public class MessageListFragment extends Fragment implements ListHolder {
}
this.activateOnItemClick = activateOnItemClick;
}
@Override
public boolean showPreviousList() {
if (backStack.isEmpty()) {
return false;
} else {
doUpdateList(backStack.pop());
return true;
}
}
@Override
public Label getCurrentLabel() {
return currentLabel;
}
}

View File

@ -1,18 +0,0 @@
package ch.dissem.apps.abit;
import android.os.Bundle;
/**
* @author Christian Basler
*/
public class SettingsActivity extends DetailActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(R.id.content, new SettingsFragment())
.commit();
}
}

View File

@ -21,14 +21,15 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.widget.Toast;
import com.mikepenz.aboutlibraries.Libs;
import com.mikepenz.aboutlibraries.LibsBuilder;
import ch.dissem.apps.abit.listener.ActionBarListener;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.apps.abit.synchronization.SyncAdapter;
import ch.dissem.bitmessage.BitmessageContext;
@ -40,26 +41,29 @@ import static ch.dissem.apps.abit.util.Constants.PREFERENCE_TRUSTED_NODE;
* @author Christian Basler
*/
public class SettingsFragment
extends PreferenceFragment
extends PreferenceFragmentCompat
implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
Preference about = findPreference("about");
about.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
new LibsBuilder()
LibsBuilder libsBuilder = new LibsBuilder()
.withActivityTitle(getActivity().getString(R.string.about))
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true)
.withAboutVersionShown(true)
.withAboutDescription(getString(R.string.about_app))
.start(getActivity());
.withAboutDescription(getString(R.string.about_app));
MainActivity activity = (MainActivity) getActivity();
if (activity.hasDetailPane()) {
activity.setDetailView(libsBuilder.supportFragment());
} else {
libsBuilder.start(getActivity());
}
return true;
}
});
@ -103,7 +107,12 @@ public class SettingsFragment
status.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
startActivity(new Intent(getActivity(), StatusActivity.class));
MainActivity activity = (MainActivity) getActivity();
if (activity.hasDetailPane()) {
activity.setDetailView(new StatusFragment());
} else {
startActivity(new Intent(getActivity(), StatusActivity.class));
}
return true;
}
});
@ -114,6 +123,10 @@ public class SettingsFragment
super.onAttach(ctx);
PreferenceManager.getDefaultSharedPreferences(ctx)
.registerOnSharedPreferenceChangeListener(this);
if (ctx instanceof ActionBarListener) {
((ActionBarListener) ctx).updateTitle(getString(R.string.settings));
}
}
@Override

View File

@ -0,0 +1,49 @@
/*
* Copyright 2016 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.apps.abit;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
public class StatusFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_status, container, false);
BitmessageContext bmc = Singleton.getBitmessageContext(inflater.getContext());
StringBuilder status = new StringBuilder();
for (BitmessageAddress address : bmc.addresses().getIdentities()) {
status.append(address.getAddress()).append('\n');
}
status.append('\n');
status.append(bmc.status());
((TextView) view.findViewById(R.id.content)).setText(status);
return view;
}
}

View File

@ -30,13 +30,11 @@ import android.widget.TextView;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action
.SwipeResultActionMoveToSwipedDirection;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionMoveToSwipedDirection;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractSwipeableItemViewHolder;
import com.h6ah4i.android.widget.advrecyclerview.utils.RecyclerViewAdapterUtils;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@ -66,7 +64,7 @@ public class SwipeableMessageAdapter
private final View.OnClickListener swipeableViewContainerOnClickListener;
private Label label;
private int selectedPosition;
private int selectedPosition = -1;
private boolean activateOnItemClick;
public void setActivateOnItemClick(boolean activateOnItemClick) {

View File

@ -303,11 +303,10 @@ public class AndroidAddressRepository implements AddressRepository {
}
}
@NonNull
@Override
public BitmessageAddress getAddress(String address) {
List<BitmessageAddress> result = find("address = '" + address + "'");
if (result.size() > 0) return result.get(0);
return new BitmessageAddress(address);
return null;
}
}

View File

@ -35,6 +35,7 @@ import java.util.UUID;
import ch.dissem.apps.abit.util.Labels;
import ch.dissem.apps.abit.util.UuidUtils;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label;
@ -154,29 +155,30 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
@Override
public int countUnread(Label label) {
String[] args;
String where;
if (label == null) {
return 0;
}
if (label == LABEL_ARCHIVE) {
where = "";
args = new String[]{
Label.Type.UNREAD.name()
};
return 0;
} else if (label == null) {
return (int) DatabaseUtils.queryNumEntries(
sql.getReadableDatabase(),
TABLE_NAME,
"id IN (SELECT message_id FROM Message_Label WHERE label_id IN (SELECT id FROM Label WHERE type=?))",
new String[]{
String.valueOf(label.getId()),
Label.Type.UNREAD.name()
}
);
} else {
where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=?) AND ";
args = new String[]{
String.valueOf(label.getId()),
Label.Type.UNREAD.name()
};
return (int) DatabaseUtils.queryNumEntries(
sql.getReadableDatabase(),
TABLE_NAME,
" id IN (SELECT message_id FROM Message_Label WHERE label_id=?) " +
"AND id IN (SELECT message_id FROM Message_Label WHERE label_id IN (SELECT id FROM Label WHERE type=?))",
new String[]{
String.valueOf(label.getId()),
Label.Type.UNREAD.name()
}
);
}
SQLiteDatabase db = sql.getReadableDatabase();
return (int) DatabaseUtils.queryNumEntries(db, TABLE_NAME,
where + "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" +
"SELECT id FROM Label WHERE type=?))",
args
);
}
@NonNull
@ -249,7 +251,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
@NonNull
protected List<Long> findIds(String where) {
private List<Long> findIds(String where) {
List<Long> result = new LinkedList<>();
// Define a projection that specifies which columns from the database
@ -266,7 +268,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
COLUMN_RECEIVED + " DESC, " + COLUMN_SENT + " DESC"
)) {
while (c.moveToNext()) {
long id = c.getLong(c.getColumnIndex(COLUMN_ID));
long id = c.getLong(0);
result.add(id);
}
}
@ -315,11 +317,21 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
builder.IV(InventoryVector.fromHash(iv));
String sender = c.getString(c.getColumnIndex(COLUMN_SENDER));
if (sender != null) {
builder.from(ctx.getAddressRepository().getAddress(sender));
BitmessageAddress address = ctx.getAddressRepository().getAddress(sender);
if (address != null) {
builder.from(address);
} else {
builder.from(new BitmessageAddress(sender));
}
}
String recipient = c.getString(c.getColumnIndex(COLUMN_RECIPIENT));
if (recipient != null) {
builder.to(ctx.getAddressRepository().getAddress(recipient));
BitmessageAddress address = ctx.getAddressRepository().getAddress(recipient);
if (address != null) {
builder.to(address);
} else {
builder.to(new BitmessageAddress(sender));
}
}
builder.ackData(c.getBlob(c.getColumnIndex(COLUMN_ACK_DATA)));
builder.sent(c.getLong(c.getColumnIndex(COLUMN_SENT)));
@ -405,7 +417,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
private void update(SQLiteDatabase db, Plaintext message) {
db.update(TABLE_NAME, getValues(message), "id = " + message.getId(), null);
db.update(TABLE_NAME, getValues(message), "id=?", new String[]{valueOf(message.getId())});
}
@Override

View File

@ -16,11 +16,16 @@
package ch.dissem.apps.abit.repository;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.UUID;
import ch.dissem.apps.abit.util.Assets;
import ch.dissem.apps.abit.util.UuidUtils;
/**
* Handles database migration and provides access.
@ -63,12 +68,37 @@ public class SqlHelper extends SQLiteOpenHelper {
executeMigration(db, "V3.4__Add_label_outbox");
case 6:
executeMigration(db, "V4.0__Create_table_message_parent");
case 7:
setMissingConversationIds(db);
default:
// Nothing to do. Let's assume we won't upgrade from a version that's newer than
// DATABASE_VERSION.
}
}
/**
* Set UUIDs for all messages that have no conversation ID
*/
private void setMissingConversationIds(SQLiteDatabase db) {
try (Cursor c = db.query(
"Message", new String[]{"id"},
"conversation IS NULL",
null, null, null, null
)) {
while (c.moveToNext()) {
long id = c.getLong(0);
setMissingConversationId(id, db);
}
}
}
private void setMissingConversationId(long id, SQLiteDatabase db) {
ContentValues values = new ContentValues(1);
values.put("conversation", UuidUtils.asBytes(UUID.randomUUID()));
db.update("Message", values, "id=?", new String[]{String.valueOf(id)});
}
private void executeMigration(SQLiteDatabase db, String name) {
for (String statement : Assets.readSqlStatements(ctx, "db/migration/" + name + ".sql")) {
db.execSQL(statement);

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_item_selected_state"
android:state_pressed="true"
android:state_selected="true"
android:state_activated="true"
android:state_active="true"
android:state_checked="true"
android:state_focused="true"
android:state_single="true"/>
<item android:drawable="@drawable/bg_item_normal_state" />
</selector>

View File

@ -1,21 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 Haruki Hasegawa
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/bg_item_selected_state"/>
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent" />
</shape>
</item>
<item android:left="4dp">
<shape android:shape="rectangle">
<solid android:color="@color/colorAccentLight" />
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/md_white_1000" />
</shape>
</item>
</layer-list>

View File

@ -1,59 +1,61 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
tools:ignore="UnusedAttribute"/>
tools:ignore="UnusedAttribute"
tools:layout_editor_absoluteX="8dp" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
android:baselineAligned="false"
android:orientation="horizontal"
android:showDividers="middle"
tools:context=".MainActivity">
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.382" />
<!--
This layout is a two-pane layout for the Messages
master/detail flow.
-->
<FrameLayout
android:id="@+id/item_list"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/toolbar"
android:background="@drawable/bg_white"
android:elevation="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
tools:context=".MessageListActivity"
tools:layout="@layout/fragment_message_list"
tools:ignore="UnusedAttribute" />
<FrameLayout
android:id="@+id/item_list"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:context=".MessageListActivity"
tools:layout="@layout/fragment_message_list"/>
<FrameLayout
android:id="@+id/message_detail_container"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_below="@+id/toolbar"
android:layout_weight="2"
android:background="@drawable/bg_white"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
tools:ignore="InconsistentLayout"
tools:layout="@layout/fragment_message_detail" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:background="@color/bg_item_selected_state">
<FrameLayout
android:id="@+id/message_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:background="@color/contentBackground"
android:elevation="2dp"
tools:layout="@layout/fragment_message_detail"
tools:ignore="InconsistentLayout,UnusedAttribute"/>
</FrameLayout>
</LinearLayout>
</RelativeLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2015 Christian Basler
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@ -16,9 +15,10 @@
-->
<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">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_item_selectable">
<ImageView
android:id="@+id/avatar"
@ -28,7 +28,7 @@
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:src="@color/colorAccent"
tools:ignore="ContentDescription"/>
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/name"
@ -44,7 +44,7 @@
android:paddingTop="0dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
tools:text="Name"/>
tools:text="Name" />
<TextView
android:id="@+id/address"
@ -57,6 +57,6 @@
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="BM-2cW0000000000000000000000000000000"/>
tools:text="BM-2cW0000000000000000000000000000000" />
</RelativeLayout>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="match_parent">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@id/android:list"
@ -13,8 +13,9 @@
android:layout_alignParentTop="true"
android:choiceMode="singleChoice"
android:clipToPadding="false"
android:listSelector="@drawable/bg_item_selected_state"
android:paddingBottom="88dp"
android:scrollbarStyle="outsideOverlay"/>
android:scrollbarStyle="outsideOverlay" />
<io.github.yavski.fabspeeddial.FabSpeedDial
android:id="@+id/fab_add_contact"
@ -27,5 +28,5 @@
app:elevation="8dp"
app:fabDrawable="@drawable/ic_action_add_contact"
app:fabGravity="bottom_end"
app:fabMenu="@menu/fab_address"/>
app:fabMenu="@menu/fab_address" />
</RelativeLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fontFamily="monospace"
android:padding="16dp"
android:text=""
android:textIsSelectable="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

View File

@ -19,8 +19,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/activatedBackgroundIndicator">
android:layout_height="wrap_content">
<ImageView
android:id="@+id/avatar"

View File

@ -6,6 +6,7 @@
<color name="colorPrimaryDarkText">#DEFFFFFF</color>
<color name="colorPrimaryLight">#FFECB3</color>
<color name="colorAccent">#607D8B</color>
<color name="colorAccentLight">#d3e0e6</color>
<color name="colorPrimaryText">#212121</color>
<color name="colorSecondaryText">#727272</color>
<color name="contentBackground">#FFFFFF</color>

View File

@ -5,6 +5,7 @@
<item name="android:activatedBackgroundIndicator">@drawable/bg_item_activated</item>
<item name="android:textColor">@color/colorPrimaryText</item>
<item name="android:textColorSecondary">@color/colorSecondaryText</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>
<style name="CustomShowcaseTheme" parent="ShowcaseView">

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!--
<ListPreference
android:key="wifi_mode"
android:title="@string/wifi_mode"
android:dialogTitle="@string/wifi_mode"
android:entries="@array/connection_modes"
android:entryValues="@array/connection_mode_values"/>
-->
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="wifi_only"
android:summary="@string/wifi_only_summary"
@ -24,7 +16,7 @@
android:key="sync_timeout"
android:summary="@string/sync_timeout_summary"
android:title="@string/sync_timeout"/>
<SwitchPreference
<SwitchPreferenceCompat
android:defaultValue="false"
android:dependency="trusted_node"
android:key="server_pow"

Binary file not shown.

View File

@ -1,6 +1,6 @@
#Tue Apr 04 00:02:32 CEST 2017
#Wed Jul 05 00:16:56 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip