UI improvements and fixes for older Android versions
This commit is contained in:
parent
1c284eba26
commit
433c757107
@ -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"
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
|
49
app/src/main/java/ch/dissem/apps/abit/StatusFragment.java
Normal file
49
app/src/main/java/ch/dissem/apps/abit/StatusFragment.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
12
app/src/main/res/drawable/bg_item_selectable.xml
Normal file
12
app/src/main/res/drawable/bg_item_selectable.xml
Normal 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>
|
@ -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>
|
||||
|
8
app/src/main/res/drawable/bg_white.xml
Normal file
8
app/src/main/res/drawable/bg_white.xml
Normal 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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
11
app/src/main/res/layout/fragment_status.xml
Normal file
11
app/src/main/res/layout/fragment_status.xml
Normal 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" />
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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"
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user