Skip to content
Snippets Groups Projects
Verified Commit 401abf2c authored by Torsten Grote's avatar Torsten Grote
Browse files

Add first onboarding screen

When the user enters a private conversation after adding her second
contact, an onboarding screen will be shown highlighting the possibility
of introducing the contacts to each other.
parent eb618915
No related branches found
No related tags found
No related merge requests found
......@@ -25,6 +25,7 @@ dependencies {
exclude module: 'recyclerview-v7'
}
compile "com.android.support:cardview-v7:$supportVersion"
compile 'com.android.support:support-annotations:23.4.0'
compile('ch.acra:acra:4.8.5') {
exclude module: 'support-v4'
exclude module: 'support-annotations'
......@@ -37,6 +38,7 @@ dependencies {
provided 'javax.annotation:jsr250-api:1.0'
compile 'com.jpardogo.materialtabstrip:library:1.1.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'uk.co.samuelwall:material-tap-target-prompt:1.3.0'
testCompile 'junit:junit:4.12'
testCompile 'net.jodah:concurrentunit:0.4.2'
......@@ -57,13 +59,14 @@ dependencyVerification {
'com.android.support:appcompat-v7:00f9d93acacd6731f309724054bf51492814b4b2869f16d7d5c0038dcb8c9a0d',
'com.android.support:preference-v14:44881bb46094e86d0bc2426f205419674a5b4eb514b44b5a4659b5de29f71eb7',
'com.android.support:design:003e0c0bea0a6891f8b2bc43f20ae7af2a49a17363e5bb10df5ee0bae12fa686',
'com.android.support:support-annotations:786ab0d060774fb95cfdaf4878771e14b85733b1af9d72a4aae762dc7c1dff9f',
'com.android.support:support-annotations:e91a88dd0c5e99069b7f09d4a46b5e06f1e9c4c72fc0a8e987e25d86af480f01',
'com.android.support:animated-vector-drawable:06d1963b85aa917099d7757e6a7b3e4dc06889413dc747f625ae8683606db3a1',
'com.android.support:support-vector-drawable:799bafe4c3de812386f0b291f744d5d6876452722dd40189b9ab87dbbf594ea1',
'com.android.support:recyclerview-v7:44040a888e23e0c93162a3377cfe06751080e3c22d369ab0d4301ef60d63b0fe',
'com.android.support:cardview-v7:4595f1c4a28cfa083b6c0920ad4d49e1c2ca4b8302a955e548f68eb63b74931b',
'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311',
'com.github.bumptech.glide:glide:76ef123957b5fbaebb05fcbe6606dd58c3bc3fcdadb257f99811d0ac9ea9b88b',
'uk.co.samuelwall:material-tap-target-prompt:f67e1caead12a914525b32cbf6da52a96b93ff89573f93cb41102ef3130fb64a',
]
}
......@@ -122,10 +125,6 @@ android {
warning 'MissingTranslation'
warning 'ImpliedQuantity'
}
dexOptions {
incremental true
}
}
task downloadTorGeoIp(type: Download) {
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/action_introduction"
android:icon="@drawable/introduction_white"
android:title="@string/introduction_button"
app:showAsAction="never"/>
android:visible="false"
app:showAsAction="never"
tools:visible="true"/>
<item
android:id="@+id/action_social_remove_person"
......
......@@ -114,6 +114,8 @@
<string name="connection_aborted_remote">Connection aborted by your contact! This could mean that someone is trying to interfere with your connection</string>
<!-- Introductions -->
<string name="introduction_onboarding_title">Introduce your contacts</string>
<string name="introduction_onboarding_text">You can introduce your contacts to each other, so they don\'t need to meet in person to connect on Briar.</string>
<string name="introduction_activity_title">Select Contact</string>
<string name="introduction_message_title">Introduce Contacts</string>
<string name="introduction_message_text">You can compose a message that will be sent to %1$s and %2$s along with your introduction:</string>
......
......@@ -10,12 +10,15 @@ import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.Toolbar;
import android.util.SparseArray;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
......@@ -62,6 +65,8 @@ import org.briarproject.api.messaging.PrivateMessage;
import org.briarproject.api.messaging.PrivateMessageFactory;
import org.briarproject.api.messaging.PrivateMessageHeader;
import org.briarproject.api.plugins.ConnectionRegistry;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.settings.SettingsManager;
import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sharing.InvitationResponse;
......@@ -84,6 +89,8 @@ import javax.inject.Inject;
import de.hdodenhof.circleimageview.CircleImageView;
import im.delight.android.identicons.IdenticonDrawable;
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.OnHidePromptListener;
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
import static android.widget.Toast.LENGTH_SHORT;
......@@ -91,6 +98,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
import static org.briarproject.android.contact.ConversationItem.OutgoingItem;
import static org.briarproject.android.fragment.SettingsFragment.SETTINGS_NAMESPACE;
public class ConversationActivity extends BriarActivity
implements EventListener, IntroductionHandler, TextInputListener {
......@@ -98,6 +106,8 @@ public class ConversationActivity extends BriarActivity
private static final Logger LOG =
Logger.getLogger(ConversationActivity.class.getName());
private static final int REQUEST_CODE_INTRODUCTION = 1;
public static final String SHOW_ONBOARDING_INTRODUCTION =
"showOnboardingIntroduction";
@Inject
AndroidNotificationManager notificationManager;
......@@ -108,6 +118,7 @@ public class ConversationActivity extends BriarActivity
protected Executor cryptoExecutor;
private ConversationAdapter adapter;
private Toolbar toolbar;
private CircleImageView toolbarAvatar;
private ImageView toolbarStatus;
private TextView toolbarTitle;
......@@ -122,6 +133,8 @@ public class ConversationActivity extends BriarActivity
@Inject
protected volatile EventBus eventBus;
@Inject
protected volatile SettingsManager settingsManager;
@Inject
volatile PrivateMessageFactory privateMessageFactory;
@Inject
protected volatile IntroductionManager introductionManager;
......@@ -150,13 +163,13 @@ public class ConversationActivity extends BriarActivity
setContentView(R.layout.activity_conversation);
// Custom Toolbar
Toolbar tb = (Toolbar) findViewById(R.id.toolbar);
if (tb != null) {
toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
toolbarAvatar =
(CircleImageView) tb.findViewById(R.id.contactAvatar);
toolbarStatus = (ImageView) tb.findViewById(R.id.contactStatus);
toolbarTitle = (TextView) tb.findViewById(R.id.contactName);
setSupportActionBar(tb);
(CircleImageView) toolbar.findViewById(R.id.contactAvatar);
toolbarStatus = (ImageView) toolbar.findViewById(R.id.contactStatus);
toolbarTitle = (TextView) toolbar.findViewById(R.id.contactName);
setSupportActionBar(toolbar);
}
ActionBar ab = getSupportActionBar();
if (ab != null) {
......@@ -222,7 +235,7 @@ public class ConversationActivity extends BriarActivity
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.conversation_actions, menu);
hideIntroductionActionWhenOneContact(
showIntroductionActionIfAvailable(
menu.findItem(R.id.action_introduction));
return super.onCreateOptionsMenu(menu);
......@@ -742,13 +755,19 @@ public class ConversationActivity extends BriarActivity
});
}
private void hideIntroductionActionWhenOneContact(final MenuItem item) {
private void showIntroductionActionIfAvailable(final MenuItem item) {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
if (contactManager.getActiveContacts().size() < 2) {
hideIntroductionAction(item);
if (contactManager.getActiveContacts().size() > 1) {
showIntroductionAction(item);
Settings settings =
settingsManager.getSettings(SETTINGS_NAMESPACE);
if (settings.getBoolean(SHOW_ONBOARDING_INTRODUCTION,
true)) {
showIntroductionOnboarding();
}
}
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
......@@ -758,11 +777,69 @@ public class ConversationActivity extends BriarActivity
});
}
private void hideIntroductionAction(final MenuItem item) {
private void showIntroductionAction(final MenuItem item) {
runOnUiThread(new Runnable() {
@Override
public void run() {
item.setVisible(true);
}
});
}
private void showIntroductionOnboarding() {
runOnUiThread(new Runnable() {
@Override
public void run() {
item.setVisible(false);
// find view of overflow icon
View target = null;
for (int i = 0; i < toolbar.getChildCount(); i++) {
if (toolbar.getChildAt(i) instanceof ActionMenuView) {
ActionMenuView menu =
(ActionMenuView) toolbar.getChildAt(i);
target = menu.getChildAt(menu.getChildCount() - 1);
break;
}
}
if (target == null) {
LOG.warning("No Overflow Icon found!");
return;
}
OnHidePromptListener listener = new OnHidePromptListener() {
@Override
public void onHidePrompt(MotionEvent motionEvent,
boolean focalClicked) {
if (focalClicked) introductionOnboardingSeen();
}
@Override
public void onHidePromptComplete() {
}
};
new MaterialTapTargetPrompt.Builder(ConversationActivity.this)
.setTarget(target)
.setPrimaryText(R.string.introduction_onboarding_title)
.setSecondaryText(R.string.introduction_onboarding_text)
.setBackgroundColourFromRes(R.color.briar_primary)
.setIcon(R.drawable.ic_more_vert_accent)
.setOnHidePromptListener(listener)
.show();
}
});
}
private void introductionOnboardingSeen() {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
Settings settings = new Settings();
settings.putBoolean(SHOW_ONBOARDING_INTRODUCTION, false);
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment