Solve conflicts

This commit is contained in:
neslihanturan 2018-03-25 20:24:46 +03:00
commit e5c8591fa7
12 changed files with 220 additions and 112 deletions

View file

@ -137,6 +137,7 @@ android {
buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\"" buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\""
buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.wikimedia.org/wikipedia/commons\"" buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.wikimedia.org/wikipedia/commons\""
buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.org/wiki/\"" buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.org/wiki/\""
buildConfigField "String", "COMMONS_URL", "\"https://commons.wikimedia.org\""
buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.org/wiki/\"" buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.org/wiki/\""
buildConfigField "String", "EVENTLOG_URL", "\"https://www.wikimedia.org/beacon/event\"" buildConfigField "String", "EVENTLOG_URL", "\"https://www.wikimedia.org/beacon/event\""
buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\"" buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\""
@ -152,6 +153,7 @@ android {
buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\"" buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\""
buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.beta.wmflabs.org/wikipedia/commons\"" buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.beta.wmflabs.org/wikipedia/commons\""
buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.beta.wmflabs.org/wiki/\"" buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.beta.wmflabs.org/wiki/\""
buildConfigField "String", "COMMONS_URL", "\"https://commons.wikimedia.beta.wmflabs.org\""
buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.beta.wmflabs.org/wiki/\"" buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.beta.wmflabs.org/wiki/\""
buildConfigField "String", "EVENTLOG_URL", "\"https://commons.wikimedia.beta.wmflabs.org/beacon/event\"" buildConfigField "String", "EVENTLOG_URL", "\"https://commons.wikimedia.beta.wmflabs.org/beacon/event\""
buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\"" buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\""

View file

@ -177,7 +177,7 @@ public class Utils {
} }
} }
public static void handleWebUrl(Context context,Uri url){ public static void handleWebUrl(Context context, Uri url) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, url); Intent browserIntent = new Intent(Intent.ACTION_VIEW, url);
if (browserIntent.resolveActivity(context.getPackageManager()) == null) { if (browserIntent.resolveActivity(context.getPackageManager()) == null) {
Toast toast = Toast.makeText(context, context.getString(R.string.no_web_browser), LENGTH_SHORT); Toast toast = Toast.makeText(context, context.getString(R.string.no_web_browser), LENGTH_SHORT);

View file

@ -23,7 +23,6 @@ import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.mediawiki.api.ApiResult; import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi; import org.mediawiki.api.MWApi;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import java.io.IOException; import java.io.IOException;
@ -41,16 +40,12 @@ import java.util.concurrent.Callable;
import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.PageTitle; import fr.free.nrw.commons.PageTitle;
import fr.free.nrw.commons.notification.Notification; import fr.free.nrw.commons.notification.Notification;
import fr.free.nrw.commons.notification.NotificationUtils;
import in.yuvi.http.fluent.Http; import in.yuvi.http.fluent.Http;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Single; import io.reactivex.Single;
import timber.log.Timber; import timber.log.Timber;
import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN;
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationFromApiResult;
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationType;
import static fr.free.nrw.commons.notification.NotificationUtils.isCommonsNotification;
/** /**
* @author Addshore * @author Addshore
*/ */
@ -434,32 +429,24 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
.param("notprop", "list") .param("notprop", "list")
.param("format", "xml") .param("format", "xml")
.param("meta", "notifications") .param("meta", "notifications")
.param("notfilter", "!read") // .param("meta", "notifications")
.param("notformat", "model")
.get() .get()
.getNode("/api/query/notifications/list"); .getNode("/api/query/notifications/list");
} catch (IOException e) { } catch (IOException e) {
Timber.e("Failed to obtain searchCategories", e); Timber.e("Failed to obtain searchCategories", e);
} }
if (notificationNode == null) { if (notificationNode == null
|| notificationNode.getDocument() == null
|| notificationNode.getDocument().getChildNodes() == null
|| notificationNode.getDocument().getChildNodes().getLength() == 0) {
return new ArrayList<>(); return new ArrayList<>();
} }
List<Notification> notifications = new ArrayList<>();
NodeList childNodes = notificationNode.getDocument().getChildNodes(); NodeList childNodes = notificationNode.getDocument().getChildNodes();
return NotificationUtils.getNotificationsFromList(context, childNodes);
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (isCommonsNotification(node)
&& !getNotificationType(node).equals(UNKNOWN)) {
notifications.add(getNotificationFromApiResult(context, node));
} }
}
return notifications;
}
@Override @Override
public boolean existingFile(String fileSha1) throws IOException { public boolean existingFile(String fileSha1) throws IOException {

View file

@ -10,12 +10,14 @@ public class Notification {
public String date; public String date;
public String description; public String description;
public String link; public String link;
public String iconUrl;
public Notification(NotificationType notificationType, String notificationText, String date, String description, String link) { public Notification(NotificationType notificationType, String notificationText, String date, String description, String link, String iconUrl) {
this.notificationType = notificationType; this.notificationType = notificationType;
this.notificationText = notificationText; this.notificationText = notificationText;
this.date = date; this.date = date;
this.description = description; this.description = description;
this.link = link; this.link = link;
this.iconUrl = iconUrl;
} }
} }

View file

@ -9,10 +9,13 @@ import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.widget.Toast; import android.view.View;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import com.pedrogomez.renderers.RVRendererAdapter; import com.pedrogomez.renderers.RVRendererAdapter;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -20,14 +23,14 @@ import javax.inject.Inject;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import timber.log.Timber; import timber.log.Timber;
import static android.widget.Toast.LENGTH_SHORT;
/** /**
* Created by root on 18.12.2017. * Created by root on 18.12.2017.
*/ */
@ -36,6 +39,8 @@ public class NotificationActivity extends NavigationBaseActivity {
NotificationAdapterFactory notificationAdapterFactory; NotificationAdapterFactory notificationAdapterFactory;
@BindView(R.id.listView) RecyclerView recyclerView; @BindView(R.id.listView) RecyclerView recyclerView;
@BindView(R.id.progressBar) ProgressBar progressBar;
@BindView(R.id.container) RelativeLayout relativeLayout;
@Inject NotificationController controller; @Inject NotificationController controller;
@ -65,14 +70,22 @@ public class NotificationActivity extends NavigationBaseActivity {
Timber.d("Add notifications"); Timber.d("Add notifications");
if(mNotificationWorkerFragment == null){ if(mNotificationWorkerFragment == null){
Observable.fromCallable(() -> controller.getNotifications()) Observable.fromCallable(() -> {
progressBar.setVisibility(View.VISIBLE);
return controller.getNotifications();
})
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(notificationList -> { .subscribe(notificationList -> {
Collections.reverse(notificationList);
Timber.d("Number of notifications is %d", notificationList.size()); Timber.d("Number of notifications is %d", notificationList.size());
initializeAndSetNotificationList(notificationList);
setAdapter(notificationList); setAdapter(notificationList);
}, throwable -> Timber.e(throwable, "Error occurred while loading notifications")); progressBar.setVisibility(View.GONE);
}, throwable -> {
Timber.e(throwable, "Error occurred while loading notifications");
ViewUtil.showSnackbar(relativeLayout, R.string.error_notifications);
progressBar.setVisibility(View.GONE);
});
} else { } else {
setAdapter(mNotificationWorkerFragment.getNotificationList()); setAdapter(mNotificationWorkerFragment.getNotificationList());
} }
@ -82,17 +95,14 @@ public class NotificationActivity extends NavigationBaseActivity {
if (url == null || url.equals("")) { if (url == null || url.equals("")) {
return; return;
} }
Intent browser = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); Utils.handleWebUrl(this, Uri.parse(url));
//check if web browser available
if(browser.resolveActivity(this.getPackageManager()) != null){
startActivity(browser);
} else {
Toast toast = Toast.makeText(this, getString(R.string.no_web_browser), LENGTH_SHORT);
toast.show();
}
} }
private void setAdapter(List<Notification> notificationList) { private void setAdapter(List<Notification> notificationList) {
if(notificationList == null || notificationList.isEmpty()) {
ViewUtil.showSnackbar(relativeLayout, R.string.no_notifications);
return;
}
notificationAdapterFactory = new NotificationAdapterFactory(notification -> { notificationAdapterFactory = new NotificationAdapterFactory(notification -> {
Timber.d("Notification clicked %s", notification.link); Timber.d("Notification clicked %s", notification.link);
handleUrl(notification.link); handleUrl(notification.link);

View file

@ -20,7 +20,6 @@ import fr.free.nrw.commons.R;
public class NotificationRenderer extends Renderer<Notification> { public class NotificationRenderer extends Renderer<Notification> {
@BindView(R.id.title) ReadMoreTextView title; @BindView(R.id.title) ReadMoreTextView title;
@BindView(R.id.description) ReadMoreTextView description;
@BindView(R.id.time) TextView time; @BindView(R.id.time) TextView time;
@BindView(R.id.icon) ImageView icon; @BindView(R.id.icon) ImageView icon;
private NotificationClicked listener; private NotificationClicked listener;
@ -48,13 +47,10 @@ public class NotificationRenderer extends Renderer<Notification> {
@Override @Override
public void render() { public void render() {
Notification notification = getContent(); Notification notification = getContent();
StringBuilder str = new StringBuilder(notification.notificationText); StringBuilder str = new StringBuilder(notification.notificationText.trim());
str.append(" " ); str.append(" ");
title.setText(str); title.setText(str);
time.setText(notification.date); time.setText(notification.date);
StringBuilder desc = new StringBuilder(notification.description);
desc.append(" ");
description.setText(desc);
switch (notification.notificationType) { switch (notification.notificationType) {
case THANK_YOU_EDIT: case THANK_YOU_EDIT:
icon.setImageResource(R.drawable.ic_edit_black_24dp); icon.setImageResource(R.drawable.ic_edit_black_24dp);

View file

@ -1,16 +1,24 @@
package fr.free.nrw.commons.notification; package fr.free.nrw.commons.notification;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import static fr.free.nrw.commons.notification.NotificationType.THANK_YOU_EDIT;
import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN;
public class NotificationUtils { public class NotificationUtils {
private static final String COMMONS_WIKI = "commonswiki"; private static final String COMMONS_WIKI = "commonswiki";
@ -29,27 +37,124 @@ public class NotificationUtils {
return NotificationType.handledValueOf(type); return NotificationType.handledValueOf(type);
} }
public static List<Notification> getNotificationsFromBundle(Context context, Node document) {
Element bundledNotifications = getBundledNotifications(document);
NodeList childNodes = bundledNotifications.getChildNodes();
List<Notification> notifications = new ArrayList<>();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (isUsefulNotification(node)) {
notifications.add(getNotificationFromApiResult(context, node));
}
}
return notifications;
}
@NonNull
public static List<Notification> getNotificationsFromList(Context context, NodeList childNodes) {
List<Notification> notifications = new ArrayList<>();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (isUsefulNotification(node)) {
if (isBundledNotification(node)) {
notifications.addAll(getNotificationsFromBundle(context, node));
} else {
notifications.add(getNotificationFromApiResult(context, node));
}
}
}
return notifications;
}
private static boolean isUsefulNotification(Node node) {
return isCommonsNotification(node)
&& !getNotificationType(node).equals(UNKNOWN)
&& !getNotificationType(node).equals(THANK_YOU_EDIT);
}
public static boolean isBundledNotification(Node document) {
Element bundleElement = getBundledNotifications(document);
if (bundleElement == null) {
return false;
}
return bundleElement.getChildNodes().getLength() > 0;
}
private static Element getBundledNotifications(Node document) {
return (Element) getNode(document, "bundledNotifications");
}
public static Notification getNotificationFromApiResult(Context context, Node document) { public static Notification getNotificationFromApiResult(Context context, Node document) {
NotificationType type = getNotificationType(document); NotificationType type = getNotificationType(document);
String notificationText = ""; String notificationText = "";
String link = getNotificationLink(document); String link = getPrimaryLink(document);
String description = getNotificationDescription(document); String description = getNotificationDescription(document);
String iconUrl = getNotificationIconUrl(document);
switch (type) { switch (type) {
case THANK_YOU_EDIT: case THANK_YOU_EDIT:
notificationText = context.getString(R.string.notifications_thank_you_edit); notificationText = context.getString(R.string.notifications_thank_you_edit);
break; break;
case EDIT_USER_TALK: case EDIT_USER_TALK:
notificationText = getUserTalkMessage(context, document); notificationText = getNotificationText(document);
break; break;
case MENTION: case MENTION:
notificationText = getMentionMessage(context, document); notificationText = getMentionMessage(context, document);
description = getMentionDescription(document);
break; break;
case WELCOME: case WELCOME:
notificationText = getWelcomeMessage(context, document); notificationText = getWelcomeMessage(context, document);
break; break;
} }
return new Notification(type, notificationText, getTimestamp(document), description, link); return new Notification(type, notificationText, getTimestamp(document), description, link, iconUrl);
}
private static String getNotificationText(Node document) {
String notificationBody = getNotificationBody(document);
if (notificationBody == null || notificationBody.trim().equals("")) {
return getNotificationHeader(document);
}
return notificationBody;
}
private static String getNotificationHeader(Node document) {
Node body = getNode(getModel(document), "header");
if (body != null) {
String textContent = body.getTextContent();
return textContent.replace("<strong>", "").replace("</strong>", "");
} else {
return "";
}
}
private static String getNotificationBody(Node document) {
Node body = getNode(getModel(document), "body");
if (body != null) {
String textContent = body.getTextContent();
return textContent.replace("<strong>", "").replace("</strong>", "");
} else {
return "";
}
}
private static String getMentionDescription(Node document) {
Node body = getNode(getModel(document), "body");
return body != null ? body.getTextContent() : "";
}
private static String getNotificationIconUrl(Node document) {
String format = "%s%s";
Node iconUrl = getNode(getModel(document), "iconUrl");
if(iconUrl == null) {
return null;
} else {
String url = iconUrl.getTextContent();
return String.format(format, BuildConfig.COMMONS_URL, url);
}
} }
public static String getMentionMessage(Context context, Node document) { public static String getMentionMessage(Context context, Node document) {
@ -57,16 +162,31 @@ public class NotificationUtils {
return String.format(format, getAgent(document), getNotificationDescription(document)); return String.format(format, getAgent(document), getNotificationDescription(document));
} }
@SuppressLint("StringFormatMatches")
public static String getUserTalkMessage(Context context, Node document) { public static String getUserTalkMessage(Context context, Node document) {
String format = context.getString(R.string.notifications_talk_page_message); String format = context.getString(R.string.notifications_talk_page_message);
return String.format(format, getAgent(document)); return String.format(format, getAgent(document));
} }
@SuppressLint("StringFormatInvalid")
public static String getWelcomeMessage(Context context, Node document) { public static String getWelcomeMessage(Context context, Node document) {
String welcomeMessageFormat = context.getString(R.string.notifications_welcome); String welcomeMessageFormat = context.getString(R.string.notifications_welcome);
return String.format(welcomeMessageFormat, getAgent(document)); return String.format(welcomeMessageFormat, getAgent(document));
} }
private static String getPrimaryLink(Node document) {
Node links = getNode(getModel(document), "links");
Element primaryLink = (Element) getNode(links, "primary");
if (primaryLink != null) {
return primaryLink.getAttribute("url");
}
return "";
}
private static Node getModel(Node document) {
return getNode(document, "_.2A.");
}
private static String getAgent(Node document) { private static String getAgent(Node document) {
Element agentElement = (Element) getNode(document, "agent"); Element agentElement = (Element) getNode(document, "agent");
if (agentElement != null) { if (agentElement != null) {
@ -83,16 +203,6 @@ public class NotificationUtils {
return ""; return "";
} }
private static String getNotificationLink(Node document) {
String format = "%s%s";
Element titleElement = (Element) getNode(document, "title");
if (titleElement != null) {
String fullName = titleElement.getAttribute("full");
return String.format(format, BuildConfig.HOME_URL, fullName);
}
return "";
}
private static String getNotificationDescription(Node document) { private static String getNotificationDescription(Node document) {
Element titleElement = (Element) getNode(document, "title"); Element titleElement = (Element) getNode(document, "title");
if (titleElement != null) { if (titleElement != null) {

View file

@ -21,9 +21,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@id/toolbar"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">

View file

@ -6,6 +6,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<RelativeLayout <RelativeLayout
android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -15,6 +16,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/listView" android:id="@+id/listView"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -45,27 +45,11 @@
android:layout_toRightOf="@id/icon" android:layout_toRightOf="@id/icon"
android:layout_toStartOf="@id/time" android:layout_toStartOf="@id/time"
android:ellipsize="end" android:ellipsize="end"
app:trimLines="2" app:trimMode="trimModeLength"
app:trimLength="60"
android:layout_alignParentTop="true"
app:colorClickableText="#969494" app:colorClickableText="#969494"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" android:textAppearance="@style/TextAppearance.AppCompat.Body2"
tools:text="@string/placeholder_place_name" tools:text="@string/placeholder_place_name"
/> />
<com.borjabravo.readmoretextview.ReadMoreTextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignEnd="@id/time"
android:layout_alignLeft="@id/title"
android:layout_alignRight="@id/time"
android:layout_alignStart="@id/title"
android:layout_below="@id/title"
android:layout_marginBottom="16dp"
android:ellipsize="end"
app:trimLines="2"
app:colorClickableText="#969494"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="@string/placeholder_place_description"
/>
</RelativeLayout> </RelativeLayout>

View file

@ -1,43 +1,50 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/drawer_main">
<item <item
android:id="@+id/action_home" android:id="@+id/action_home"
android:icon="@drawable/ic_home_black_24dp" android:icon="@drawable/ic_home_black_24dp"
android:title="@string/navigation_item_home"/> android:title="@string/navigation_item_home" />
<item <item
android:id="@+id/action_nearby" android:id="@+id/action_nearby"
android:icon="@drawable/ic_location_black_24dp" android:icon="@drawable/ic_location_black_24dp"
android:title="@string/navigation_item_nearby"/> android:title="@string/navigation_item_nearby" />
</group>
<group android:id="@+id/drawer_account">
<item <item
android:id="@+id/action_notifications" android:id="@+id/action_notifications"
android:icon="@drawable/ic_notifications_black_24dp" android:icon="@drawable/ic_notifications_black_24dp"
android:title="@string/navigation_item_notification"/> android:title="@string/navigation_item_notification" />
<item
android:id="@+id/action_about"
android:icon="@drawable/ic_info_outline_black_24dp"
android:title="@string/navigation_item_about"/>
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_black_24dp" android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/navigation_item_settings"/> android:title="@string/navigation_item_settings" />
</group>
<group android:id="@+id/drawer_contact">
<item
android:id="@+id/action_about"
android:icon="@drawable/ic_info_outline_black_24dp"
android:title="@string/navigation_item_about" />
<item <item
android:id="@+id/action_introduction" android:id="@+id/action_introduction"
android:icon="@drawable/ic_help_black_24dp" android:icon="@drawable/ic_help_black_24dp"
android:title="@string/navigation_item_info"/> android:title="@string/navigation_item_info" />
<item <item
android:id="@+id/action_feedback" android:id="@+id/action_feedback"
android:icon="@drawable/ic_feedback_black_24dp" android:icon="@drawable/ic_feedback_black_24dp"
android:title="@string/navigation_item_feedback"/> android:title="@string/navigation_item_feedback" />
</group>
<group android:id="@+id/drawer_logout">
<item <item
android:id="@+id/action_logout" android:id="@+id/action_logout"
android:icon="@drawable/ic_exit_to_app_black_24dp" android:icon="@drawable/ic_exit_to_app_black_24dp"
android:title="@string/navigation_item_logout"/> android:title="@string/navigation_item_logout" />
</group>
</menu> </menu>

View file

@ -256,6 +256,8 @@
<string name="no_internet">Internet unavailable</string> <string name="no_internet">Internet unavailable</string>
<string name="internet_established">Internet available</string> <string name="internet_established">Internet available</string>
<string name="error_notifications">Error fetching notifications</string>
<string name="no_notifications">No notifications found</string>
<string name="about_translate"><u>Translate</u></string> <string name="about_translate"><u>Translate</u></string>
<string name="about_translate_title">Languages</string> <string name="about_translate_title">Languages</string>