diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 83636618ba692cb0e048add10f01a9b752ff007d..b15bdf91c6c211e8b0a9ce4cab67c8df019359bf 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -7,7 +7,7 @@ <string name="choose_nickname">Choose your nickname:</string> <string name="choose_password">Choose your password:</string> <string name="confirm_password">Confirm your password:</string> - <string name="format_min_password">Password must be at least %1$d characters long.</string> + <string name="format_min_password">Password must be at least %1$d characters long</string> <string name="enter_password">Enter your password:</string> <string name="try_again">Wrong password, try again:</string> <string name="expiry_warning">This software has expired.\nPlease install a newer version.</string> @@ -32,6 +32,7 @@ <string name="bluetooth_disabled">Bluetooth is OFF</string> <string name="bluetooth_not_discoverable">Bluetooth is NOT DISCOVERABLE</string> <string name="bluetooth_enabled">Bluetooth is discoverable</string> + <string name="fact_to_face">For security reasons you must be face-to-face with someone to add them as a contact</string> <string name="continue_button">Continue</string> <string name="your_invitation_code">Your invitation code is</string> <string name="enter_invitation_code">Please enter your contact\'s invitation code:</string> @@ -69,12 +70,14 @@ <string name="group_visible_to_some">Share this group with chosen contacts</string> <string name="new_post_title">New Post</string> <string name="new_group_item">New group\u2026</string> + <string name="manage_subscriptions_title">Manage Subscriptions</string> + <string name="no_groups_available">No groups available from contacts</string> <string name="blogs_title">Blogs</string> <plurals name="blogs_available"> <item quantity="one">%1$d blog available from contacts</item> <item quantity="other">%1$d blogs available from contacts</item> </plurals> - <string name="manage_subscriptions_title">Manage Subscriptions</string> + <string name="no_blogs_available">No blogs available from contacts</string> <string name="subscribed_all">Subscribed, shared with all contacts</string> <string name="subscribed_some">Subscribed, shared with chosen contacts</string> <string name="not_subscribed">Not subscribed</string> diff --git a/briar-android/src/net/sf/briar/android/ManageGroupsAdapter.java b/briar-android/src/net/sf/briar/android/ManageGroupsAdapter.java deleted file mode 100644 index cddca6333345a8a5c1a9fcd13dc0005893096066..0000000000000000000000000000000000000000 --- a/briar-android/src/net/sf/briar/android/ManageGroupsAdapter.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.sf.briar.android; - -import static android.view.View.INVISIBLE; -import static android.widget.LinearLayout.HORIZONTAL; -import static android.widget.LinearLayout.VERTICAL; - -import java.util.ArrayList; - -import net.sf.briar.R; -import net.sf.briar.api.messaging.GroupStatus; -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ListAdapter; -import android.widget.TextView; - -public class ManageGroupsAdapter extends ArrayAdapter<GroupStatus> -implements ListAdapter { - - public ManageGroupsAdapter(Context ctx) { - super(ctx, android.R.layout.simple_expandable_list_item_1, - new ArrayList<GroupStatus>()); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final GroupStatus item = getItem(position); - Context ctx = getContext(); - - LinearLayout layout = new LinearLayout(ctx); - layout.setOrientation(HORIZONTAL); - - ImageView subscribed = new ImageView(ctx); - subscribed.setPadding(5, 5, 5, 5); - subscribed.setImageResource(R.drawable.navigation_accept); - if(!item.isSubscribed()) subscribed.setVisibility(INVISIBLE); - layout.addView(subscribed); - - LinearLayout innerLayout = new LinearLayout(ctx); - innerLayout.setOrientation(VERTICAL); - - TextView name = new TextView(ctx); - name.setTextSize(18); - name.setMaxLines(1); - name.setPadding(0, 10, 10, 10); - name.setText(item.getGroup().getName()); - innerLayout.addView(name); - - TextView status = new TextView(ctx); - status.setTextSize(14); - status.setPadding(0, 0, 10, 10); - if(item.isSubscribed()) { - if(item.isVisibleToAll()) status.setText(R.string.subscribed_all); - else status.setText(R.string.subscribed_some); - } else { - status.setText(R.string.not_subscribed); - } - innerLayout.addView(status); - layout.addView(innerLayout); - - return layout; - } -} diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogListAdapter.java b/briar-android/src/net/sf/briar/android/blogs/BlogListAdapter.java index 4721572612c94d4b23174e7f2c9cda9788db4aae..470ee405c874e902ae2b6d4be9efd062e0a3e17c 100644 --- a/briar-android/src/net/sf/briar/android/blogs/BlogListAdapter.java +++ b/briar-android/src/net/sf/briar/android/blogs/BlogListAdapter.java @@ -137,7 +137,7 @@ class BlogListAdapter extends BaseAdapter { @Override public boolean isEmpty() { - return false; + return list.isEmpty() && available == 0; } public void remove(BlogListItem item) { diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java index e464217cabf0580cb7728b355cc2d2ab3f288904..539203a68e296aed93020c1e76087dfb425521ca 100644 --- a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java +++ b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java @@ -2,6 +2,7 @@ package net.sf.briar.android.blogs; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; +import static net.sf.briar.android.blogs.ManageBlogsItem.NONE; import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH; import java.util.ArrayList; @@ -15,7 +16,6 @@ import java.util.logging.Logger; import net.sf.briar.android.BriarFragmentActivity; import net.sf.briar.android.BriarService; import net.sf.briar.android.BriarService.BriarServiceConnection; -import net.sf.briar.android.ManageGroupsAdapter; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; @@ -44,7 +44,7 @@ implements DatabaseListener, OnItemClickListener { private final BriarServiceConnection serviceConnection = new BriarServiceConnection(); - private ManageGroupsAdapter adapter = null; + private ManageBlogsAdapter adapter = null; private ListView list = null; // Fields that are accessed from background threads must be volatile @@ -55,7 +55,7 @@ implements DatabaseListener, OnItemClickListener { public void onCreate(Bundle state) { super.onCreate(null); - adapter = new ManageGroupsAdapter(this); + adapter = new ManageBlogsAdapter(this); list = new ListView(this); list.setLayoutParams(MATCH_MATCH); list.setAdapter(adapter); @@ -105,7 +105,8 @@ implements DatabaseListener, OnItemClickListener { runOnUiThread(new Runnable() { public void run() { adapter.clear(); - for(GroupStatus g : available) adapter.add(g); + for(GroupStatus g : available) + adapter.add(new ManageBlogsItem(g)); adapter.sort(ItemComparator.INSTANCE); adapter.notifyDataSetChanged(); } @@ -146,24 +147,29 @@ implements DatabaseListener, OnItemClickListener { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - GroupStatus item = adapter.getItem(position); - Group g = item.getGroup(); + ManageBlogsItem item = adapter.getItem(position); + if(item == NONE) return; + GroupStatus s = item.getGroupStatus(); + Group g = s.getGroup(); Intent i = new Intent(this, ConfigureBlogActivity.class); i.putExtra("net.sf.briar.GROUP_ID", g.getId().getBytes()); i.putExtra("net.sf.briar.GROUP_NAME", g.getName()); i.putExtra("net.sf.briar.PUBLIC_KEY", g.getPublicKey()); - i.putExtra("net.sf.briar.SUBSCRIBED", item.isSubscribed()); - i.putExtra("net.sf.briar.VISIBLE_TO_ALL", item.isVisibleToAll()); + i.putExtra("net.sf.briar.SUBSCRIBED", s.isSubscribed()); + i.putExtra("net.sf.briar.VISIBLE_TO_ALL", s.isVisibleToAll()); startActivity(i); } - private static class ItemComparator implements Comparator<GroupStatus> { + private static class ItemComparator implements Comparator<ManageBlogsItem> { private static final ItemComparator INSTANCE = new ItemComparator(); - public int compare(GroupStatus a, GroupStatus b) { - String aName = a.getGroup().getName(); - String bName = b.getGroup().getName(); + public int compare(ManageBlogsItem a, ManageBlogsItem b) { + if(a == b) return 0; + if(a == NONE) return 1; + if(b == NONE) return -1; + String aName = a.getGroupStatus().getGroup().getName(); + String bName = b.getGroupStatus().getGroup().getName(); return String.CASE_INSENSITIVE_ORDER.compare(aName, bName); } } diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsAdapter.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..6afe109f1774b0edb1f196d8f5ef386375840510 --- /dev/null +++ b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsAdapter.java @@ -0,0 +1,112 @@ +package net.sf.briar.android.blogs; + +import static android.view.Gravity.CENTER; +import static android.view.View.INVISIBLE; +import static android.widget.LinearLayout.HORIZONTAL; +import static android.widget.LinearLayout.VERTICAL; +import static net.sf.briar.android.blogs.ManageBlogsItem.NONE; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import net.sf.briar.R; +import net.sf.briar.api.messaging.GroupStatus; +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +class ManageBlogsAdapter extends BaseAdapter { + + private final Context ctx; + private final List<ManageBlogsItem> list = new ArrayList<ManageBlogsItem>(); + + ManageBlogsAdapter(Context ctx) { + this.ctx = ctx; + } + + public void add(ManageBlogsItem item) { + list.add(item); + } + + public void clear() { + list.clear(); + } + + public int getCount() { + return list.isEmpty() ? 1 : list.size(); + } + + public ManageBlogsItem getItem(int position) { + return list.isEmpty() ? NONE : list.get(position); + } + + public long getItemId(int position) { + return android.R.layout.simple_expandable_list_item_1; + } + + public View getView(int position, View convertView, ViewGroup parent) { + ManageBlogsItem item = getItem(position); + + if(item == NONE) { + TextView none = new TextView(ctx); + none.setGravity(CENTER); + none.setTextSize(18); + none.setPadding(10, 10, 10, 10); + none.setText(R.string.no_blogs_available); + return none; + } + + GroupStatus s = item.getGroupStatus(); + LinearLayout layout = new LinearLayout(ctx); + layout.setOrientation(HORIZONTAL); + + ImageView subscribed = new ImageView(ctx); + subscribed.setPadding(5, 5, 5, 5); + subscribed.setImageResource(R.drawable.navigation_accept); + if(!s.isSubscribed()) subscribed.setVisibility(INVISIBLE); + layout.addView(subscribed); + + LinearLayout innerLayout = new LinearLayout(ctx); + innerLayout.setOrientation(VERTICAL); + + TextView name = new TextView(ctx); + name.setTextSize(18); + name.setMaxLines(1); + name.setPadding(0, 10, 10, 10); + name.setText(s.getGroup().getName()); + innerLayout.addView(name); + + TextView status = new TextView(ctx); + status.setTextSize(14); + status.setPadding(0, 0, 10, 10); + if(s.isSubscribed()) { + if(s.isVisibleToAll()) status.setText(R.string.subscribed_all); + else status.setText(R.string.subscribed_some); + } else { + status.setText(R.string.not_subscribed); + } + innerLayout.addView(status); + layout.addView(innerLayout); + + return layout; + } + + @Override + public boolean isEmpty() { + return false; + } + + public void remove(ManageBlogsItem item) { + list.remove(item); + } + + public void sort(Comparator<ManageBlogsItem> comparator) { + Collections.sort(list, comparator); + } +} diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsItem.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsItem.java new file mode 100644 index 0000000000000000000000000000000000000000..dfa61ea77db41184339d4b5e82cf4b0d95372084 --- /dev/null +++ b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsItem.java @@ -0,0 +1,18 @@ +package net.sf.briar.android.blogs; + +import net.sf.briar.api.messaging.GroupStatus; + +class ManageBlogsItem { + + static final ManageBlogsItem NONE = new ManageBlogsItem(null); + + private final GroupStatus status; + + ManageBlogsItem(GroupStatus status) { + this.status = status; + } + + GroupStatus getGroupStatus() { + return status; + } +} diff --git a/briar-android/src/net/sf/briar/android/groups/GroupListAdapter.java b/briar-android/src/net/sf/briar/android/groups/GroupListAdapter.java index e6bc316444bb2f861ede3cbc938ead219687fad7..0c34a0e6ba6a554bb7e61c57128d9936b6347c75 100644 --- a/briar-android/src/net/sf/briar/android/groups/GroupListAdapter.java +++ b/briar-android/src/net/sf/briar/android/groups/GroupListAdapter.java @@ -137,7 +137,7 @@ class GroupListAdapter extends BaseAdapter { @Override public boolean isEmpty() { - return false; + return list.isEmpty() && available == 0; } public void remove(GroupListItem item) { diff --git a/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java b/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java index 421086dbb32faf9e4eca00468420bca80ef0e7d9..976f8b9a55b54f1d3aac91630ed4100824a65bf1 100644 --- a/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java +++ b/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java @@ -2,6 +2,7 @@ package net.sf.briar.android.groups; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; +import static net.sf.briar.android.groups.ManageGroupsItem.NONE; import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH; import java.util.ArrayList; @@ -15,7 +16,6 @@ import java.util.logging.Logger; import net.sf.briar.android.BriarFragmentActivity; import net.sf.briar.android.BriarService; import net.sf.briar.android.BriarService.BriarServiceConnection; -import net.sf.briar.android.ManageGroupsAdapter; import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; @@ -105,7 +105,8 @@ implements DatabaseListener, OnItemClickListener { runOnUiThread(new Runnable() { public void run() { adapter.clear(); - for(GroupStatus g : available) adapter.add(g); + for(GroupStatus g : available) + adapter.add(new ManageGroupsItem(g)); adapter.sort(ItemComparator.INSTANCE); adapter.notifyDataSetChanged(); } @@ -146,23 +147,29 @@ implements DatabaseListener, OnItemClickListener { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - GroupStatus item = adapter.getItem(position); - Group g = item.getGroup(); + ManageGroupsItem item = adapter.getItem(position); + if(item == NONE) return; + GroupStatus s = item.getGroupStatus(); + Group g = s.getGroup(); Intent i = new Intent(this, ConfigureGroupActivity.class); i.putExtra("net.sf.briar.GROUP_ID", g.getId().getBytes()); i.putExtra("net.sf.briar.GROUP_NAME", g.getName()); - i.putExtra("net.sf.briar.SUBSCRIBED", item.isSubscribed()); - i.putExtra("net.sf.briar.VISIBLE_TO_ALL", item.isVisibleToAll()); + i.putExtra("net.sf.briar.SUBSCRIBED", s.isSubscribed()); + i.putExtra("net.sf.briar.VISIBLE_TO_ALL", s.isVisibleToAll()); startActivity(i); } - private static class ItemComparator implements Comparator<GroupStatus> { + private static class ItemComparator + implements Comparator<ManageGroupsItem> { private static final ItemComparator INSTANCE = new ItemComparator(); - public int compare(GroupStatus a, GroupStatus b) { - String aName = a.getGroup().getName(); - String bName = b.getGroup().getName(); + public int compare(ManageGroupsItem a, ManageGroupsItem b) { + if(a == b) return 0; + if(a == NONE) return 1; + if(b == NONE) return -1; + String aName = a.getGroupStatus().getGroup().getName(); + String bName = b.getGroupStatus().getGroup().getName(); return String.CASE_INSENSITIVE_ORDER.compare(aName, bName); } } diff --git a/briar-android/src/net/sf/briar/android/groups/ManageGroupsAdapter.java b/briar-android/src/net/sf/briar/android/groups/ManageGroupsAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..77565ef61c75aada86a6d24a3b87cc75e2d2b1de --- /dev/null +++ b/briar-android/src/net/sf/briar/android/groups/ManageGroupsAdapter.java @@ -0,0 +1,113 @@ +package net.sf.briar.android.groups; + +import static android.view.Gravity.CENTER; +import static android.view.View.INVISIBLE; +import static android.widget.LinearLayout.HORIZONTAL; +import static android.widget.LinearLayout.VERTICAL; +import static net.sf.briar.android.groups.ManageGroupsItem.NONE; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import net.sf.briar.R; +import net.sf.briar.api.messaging.GroupStatus; +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +class ManageGroupsAdapter extends BaseAdapter { + + private final Context ctx; + private final List<ManageGroupsItem> list = + new ArrayList<ManageGroupsItem>(); + + ManageGroupsAdapter(Context ctx) { + this.ctx = ctx; + } + + public void add(ManageGroupsItem item) { + list.add(item); + } + + public void clear() { + list.clear(); + } + + public int getCount() { + return list.isEmpty() ? 1 : list.size(); + } + + public ManageGroupsItem getItem(int position) { + return list.isEmpty() ? NONE : list.get(position); + } + + public long getItemId(int position) { + return android.R.layout.simple_expandable_list_item_1; + } + + public View getView(int position, View convertView, ViewGroup parent) { + ManageGroupsItem item = getItem(position); + + if(item == NONE) { + TextView none = new TextView(ctx); + none.setGravity(CENTER); + none.setTextSize(18); + none.setPadding(10, 10, 10, 10); + none.setText(R.string.no_groups_available); + return none; + } + + GroupStatus s = item.getGroupStatus(); + LinearLayout layout = new LinearLayout(ctx); + layout.setOrientation(HORIZONTAL); + + ImageView subscribed = new ImageView(ctx); + subscribed.setPadding(5, 5, 5, 5); + subscribed.setImageResource(R.drawable.navigation_accept); + if(!s.isSubscribed()) subscribed.setVisibility(INVISIBLE); + layout.addView(subscribed); + + LinearLayout innerLayout = new LinearLayout(ctx); + innerLayout.setOrientation(VERTICAL); + + TextView name = new TextView(ctx); + name.setTextSize(18); + name.setMaxLines(1); + name.setPadding(0, 10, 10, 10); + name.setText(s.getGroup().getName()); + innerLayout.addView(name); + + TextView status = new TextView(ctx); + status.setTextSize(14); + status.setPadding(0, 0, 10, 10); + if(s.isSubscribed()) { + if(s.isVisibleToAll()) status.setText(R.string.subscribed_all); + else status.setText(R.string.subscribed_some); + } else { + status.setText(R.string.not_subscribed); + } + innerLayout.addView(status); + layout.addView(innerLayout); + + return layout; + } + + @Override + public boolean isEmpty() { + return false; + } + + public void remove(ManageGroupsItem item) { + list.remove(item); + } + + public void sort(Comparator<ManageGroupsItem> comparator) { + Collections.sort(list, comparator); + } +} diff --git a/briar-android/src/net/sf/briar/android/groups/ManageGroupsItem.java b/briar-android/src/net/sf/briar/android/groups/ManageGroupsItem.java new file mode 100644 index 0000000000000000000000000000000000000000..29b19baa057eae534a196e648a6a545575caaa85 --- /dev/null +++ b/briar-android/src/net/sf/briar/android/groups/ManageGroupsItem.java @@ -0,0 +1,18 @@ +package net.sf.briar.android.groups; + +import net.sf.briar.api.messaging.GroupStatus; + +class ManageGroupsItem { + + static final ManageGroupsItem NONE = new ManageGroupsItem(null); + + private final GroupStatus status; + + ManageGroupsItem(GroupStatus status) { + this.status = status; + } + + GroupStatus getGroupStatus() { + return status; + } +} diff --git a/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java b/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java index 39698b0e144628d0fa651b5c8c36d3e7e4d2a1d8..90343a0225c00dc34cc7eead64faedf135653d8e 100644 --- a/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java +++ b/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java @@ -63,6 +63,13 @@ OnClickListener { bluetooth.init(this); addView(bluetooth); + TextView faceToFace = new TextView(ctx); + faceToFace.setGravity(CENTER); + faceToFace.setTextSize(14); + faceToFace.setPadding(10, 10, 10, 10); + faceToFace.setText(R.string.fact_to_face); + addView(faceToFace); + continueButton = new Button(ctx); continueButton.setLayoutParams(WRAP_WRAP); continueButton.setText(R.string.continue_button);