From 90400269655dced1fdde12f39ee0dfbed1501b1d Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Wed, 11 Nov 2015 21:03:03 +0100 Subject: [PATCH] Select contact and send message --- .../apps/abit/ComposeMessageFragment.java | 71 ++++++++-- .../dissem/apps/abit/MessageListActivity.java | 67 ++++++---- .../dissem/apps/abit/MessageListFragment.java | 4 +- .../apps/abit/SubscriptionDetailFragment.java | 2 +- .../apps/abit/SubscriptionListFragment.java | 2 +- .../apps/abit/adapter/ContactAdapter.java | 124 ++++++++++++++++++ .../apps/abit/service/BitmessageService.java | 5 + app/src/main/res/layout/contact_row.xml | 65 +++++++++ .../res/layout/fragment_compose_message.xml | 66 +++++----- ...detail.xml => fragment_contact_detail.xml} | 2 +- ...ribtions.xml => fragment_contact_list.xml} | 0 app/src/main/res/values-de/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + 13 files changed, 341 insertions(+), 73 deletions(-) create mode 100644 app/src/main/java/ch/dissem/apps/abit/adapter/ContactAdapter.java create mode 100644 app/src/main/res/layout/contact_row.xml rename app/src/main/res/layout/{fragment_subscription_detail.xml => fragment_contact_detail.xml} (98%) rename app/src/main/res/layout/{fragment_subscribtions.xml => fragment_contact_list.xml} (100%) diff --git a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java index 88145fb..e262d29 100644 --- a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java @@ -2,11 +2,21 @@ package ch.dissem.apps.abit; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.view.*; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; +import android.widget.AdapterView; +import android.widget.AutoCompleteTextView; import android.widget.EditText; -import android.widget.Toast; -import ch.dissem.bitmessage.BitmessageContext; + +import java.util.List; + +import ch.dissem.apps.abit.adapter.ContactAdapter; +import ch.dissem.apps.abit.service.Singleton; import ch.dissem.bitmessage.entity.BitmessageAddress; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_IDENTITY; @@ -16,9 +26,11 @@ import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_RECIPIENT; * Compose a new message. */ public class ComposeMessageFragment extends Fragment { - private BitmessageContext bmCtx; private BitmessageAddress identity; private BitmessageAddress recipient; + private AutoCompleteTextView recipientInput; + private EditText subjectInput; + private EditText bodyInput; /** * Mandatory empty constructor for the fragment manager to instantiate the @@ -33,10 +45,14 @@ public class ComposeMessageFragment extends Fragment { if (getArguments() != null) { if (getArguments().containsKey(EXTRA_IDENTITY)) { identity = (BitmessageAddress) getArguments().getSerializable(EXTRA_IDENTITY); + } else { + throw new RuntimeException("No identity set for ComposeMessageFragment"); } if (getArguments().containsKey(EXTRA_RECIPIENT)) { recipient = (BitmessageAddress) getArguments().getSerializable(EXTRA_RECIPIENT); } + } else { + throw new RuntimeException("No identity set for ComposeMessageFragment"); } setHasOptionsMenu(true); } @@ -45,13 +61,32 @@ public class ComposeMessageFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_compose_message, container, false); + recipientInput = (AutoCompleteTextView) rootView.findViewById(R.id.recipient); + final ContactAdapter adapter = new ContactAdapter(getContext()); + recipientInput.setAdapter(adapter); + recipientInput.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + recipient = adapter.getItem(position); + } + }); + recipientInput.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + recipient = adapter.getItem(position); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); if (recipient != null) { - EditText recipientInput = (EditText) rootView.findViewById(R.id.recipient); recipientInput.setText(recipient.toString()); } - EditText body = (EditText) rootView.findViewById(R.id.body); - body.setInputType(EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); - body.setImeOptions(EditorInfo.IME_ACTION_SEND | EditorInfo.IME_FLAG_NO_ENTER_ACTION); + subjectInput = (EditText) rootView.findViewById(R.id.subject); + bodyInput = (EditText) rootView.findViewById(R.id.body); +// bodyInput.setInputType(EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); +// bodyInput.setImeOptions(EditorInfo.IME_ACTION_SEND | EditorInfo.IME_FLAG_NO_ENTER_ACTION); return rootView; } @@ -65,7 +100,25 @@ public class ComposeMessageFragment extends Fragment { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.send: - Toast.makeText(getActivity(), "TODO: Send", Toast.LENGTH_SHORT).show(); + String inputString = recipientInput.getText().toString(); + if (recipient == null || !recipient.toString().equals(inputString)) { + try { + recipient = new BitmessageAddress(inputString); + } catch (Exception e) { + List contacts = Singleton.getAddressRepository(getContext()).getContacts(); + for (BitmessageAddress contact : contacts) { + if (inputString.equalsIgnoreCase(contact.getAlias())) { + recipient = contact; + if (inputString.equals(contact.getAlias())) + break; + } + } + } + } + Singleton.getBitmessageContext(getContext()).send(identity, recipient, + subjectInput.getText().toString(), + bodyInput.getText().toString()); + getActivity().finish(); return true; default: return super.onOptionsItemSelected(item); diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java b/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java index b8a359f..b21acb1 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageListActivity.java @@ -114,6 +114,7 @@ public class MessageListActivity extends AppCompatActivity private MessageRepository messageRepo; private AddressRepository addressRepo; + private BitmessageAddress selectedIdentity; @Override protected void onCreate(Bundle savedInstanceState) { @@ -224,38 +225,50 @@ public class MessageListActivity extends AppCompatActivity } catch (RemoteException e) { LOG.error(e.getMessage(), e); } + } else if (profile instanceof ProfileDrawerItem) { + Object tag = ((ProfileDrawerItem) profile).getTag(); + if (tag instanceof BitmessageAddress) { + selectedIdentity = (BitmessageAddress) tag; + } } // false if it should close the drawer return false; } }) .build(); + if (profiles.size() > 0) { + accountHeader.setActiveProfile(profiles.get(0), true); + } incomingHandler.updateAccountHeader(accountHeader); ArrayList drawerItems = new ArrayList<>(); for (Label label : messageRepo.getLabels()) { PrimaryDrawerItem item = new PrimaryDrawerItem().withName(label.toString()).withTag(label); - switch (label.getType()) { - case INBOX: - item.withIcon(GoogleMaterial.Icon.gmd_inbox); - break; - case DRAFT: - item.withIcon(CommunityMaterial.Icon.cmd_file); - break; - case SENT: - item.withIcon(CommunityMaterial.Icon.cmd_send); - break; - case BROADCAST: - item.withIcon(CommunityMaterial.Icon.cmd_rss); - break; - case UNREAD: - item.withIcon(GoogleMaterial.Icon.gmd_markunread_mailbox); - break; - case TRASH: - item.withIcon(GoogleMaterial.Icon.gmd_delete); - break; - default: - item.withIcon(CommunityMaterial.Icon.cmd_label); + if (label.getType() == null) { + item.withIcon(CommunityMaterial.Icon.cmd_label); + } else { + switch (label.getType()) { + case INBOX: + item.withIcon(GoogleMaterial.Icon.gmd_inbox); + break; + case DRAFT: + item.withIcon(CommunityMaterial.Icon.cmd_file); + break; + case SENT: + item.withIcon(CommunityMaterial.Icon.cmd_send); + break; + case BROADCAST: + item.withIcon(CommunityMaterial.Icon.cmd_rss); + break; + case UNREAD: + item.withIcon(GoogleMaterial.Icon.gmd_markunread_mailbox); + break; + case TRASH: + item.withIcon(GoogleMaterial.Icon.gmd_delete); + break; + default: + item.withIcon(CommunityMaterial.Icon.cmd_label); + } } drawerItems.add(item); } @@ -273,8 +286,8 @@ public class MessageListActivity extends AppCompatActivity .withDrawerItems(drawerItems) .addStickyDrawerItems( new PrimaryDrawerItem() - .withName(R.string.subscriptions) - .withIcon(CommunityMaterial.Icon.cmd_rss_box), + .withName(R.string.contacts_and_subscriptions) + .withIcon(GoogleMaterial.Icon.gmd_contacts), new PrimaryDrawerItem() .withName(R.string.settings) .withIcon(GoogleMaterial.Icon.gmd_settings), @@ -313,7 +326,7 @@ public class MessageListActivity extends AppCompatActivity } else if (item instanceof Nameable) { Nameable ni = (Nameable) item; switch (ni.getNameRes()) { - case R.string.subscriptions: + case R.string.contacts_and_subscriptions: if (!(getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof SubscriptionListFragment)) { changeList(new SubscriptionListFragment()); } else { @@ -416,6 +429,10 @@ public class MessageListActivity extends AppCompatActivity super.onStop(); } + public BitmessageAddress getSelectedIdentity() { + return selectedIdentity; + } + private static class IncomingHandler extends Handler { private WeakReference accountHeaderRef; @@ -423,7 +440,7 @@ public class MessageListActivity extends AppCompatActivity accountHeaderRef = new WeakReference<>(null); } - public void updateAccountHeader(AccountHeader accountHeader){ + public void updateAccountHeader(AccountHeader accountHeader) { accountHeaderRef = new WeakReference<>(accountHeader); } diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java index 802b901..9e6d1db 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java @@ -113,7 +113,9 @@ public class MessageListFragment extends AbstractItemListFragment { fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - startActivity(new Intent(getActivity().getApplicationContext(), ComposeMessageActivity.class)); + Intent intent = new Intent(getActivity().getApplicationContext(), ComposeMessageActivity.class); + intent.putExtra(ComposeMessageActivity.EXTRA_IDENTITY, ((MessageListActivity)getActivity()).getSelectedIdentity()); + startActivity(intent); } }); diff --git a/app/src/main/java/ch/dissem/apps/abit/SubscriptionDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/SubscriptionDetailFragment.java index 0fa31e8..50d7c76 100644 --- a/app/src/main/java/ch/dissem/apps/abit/SubscriptionDetailFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/SubscriptionDetailFragment.java @@ -74,7 +74,7 @@ public class SubscriptionDetailFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_subscription_detail, container, false); + View rootView = inflater.inflate(R.layout.fragment_contact_detail, container, false); // Show the dummy content as text in a TextView. if (item != null) { diff --git a/app/src/main/java/ch/dissem/apps/abit/SubscriptionListFragment.java b/app/src/main/java/ch/dissem/apps/abit/SubscriptionListFragment.java index 18fa320..4da7c4e 100644 --- a/app/src/main/java/ch/dissem/apps/abit/SubscriptionListFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/SubscriptionListFragment.java @@ -103,7 +103,7 @@ public class SubscriptionListFragment extends AbstractItemListFragment<Bitmessag @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_subscribtions, container, false); + View rootView = inflater.inflate(R.layout.fragment_contact_list, container, false); return rootView; } diff --git a/app/src/main/java/ch/dissem/apps/abit/adapter/ContactAdapter.java b/app/src/main/java/ch/dissem/apps/abit/adapter/ContactAdapter.java new file mode 100644 index 0000000..2d0946e --- /dev/null +++ b/app/src/main/java/ch/dissem/apps/abit/adapter/ContactAdapter.java @@ -0,0 +1,124 @@ +package ch.dissem.apps.abit.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import ch.dissem.apps.abit.Identicon; +import ch.dissem.apps.abit.R; +import ch.dissem.apps.abit.service.Singleton; +import ch.dissem.bitmessage.entity.BitmessageAddress; + +/** + * An adapter for contacts. Can be filtered by alias or address. + */ +public class ContactAdapter extends BaseAdapter implements Filterable { + private final LayoutInflater inflater; + private final List<BitmessageAddress> originalData; + private List<BitmessageAddress> data; + + public ContactAdapter(Context ctx) { + inflater = LayoutInflater.from(ctx); + originalData = Singleton.getAddressRepository(ctx).getContacts(); + data = originalData; + } + + @Override + public int getCount() { + return data.size(); + } + + @Override + public BitmessageAddress getItem(int position) { + return data.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = inflater.inflate(R.layout.contact_row, parent, false); + } + BitmessageAddress item = getItem(position); + ((ImageView) convertView.findViewById(R.id.avatar)).setImageDrawable(new Identicon(item)); + ((TextView) convertView.findViewById(R.id.name)).setText(item.toString()); + ((TextView) convertView.findViewById(R.id.address)).setText(item.getAddress()); + return convertView; + } + + @Override + public Filter getFilter() { + return new ContactFilter(); + } + + private class ContactFilter extends Filter { + @Override + protected FilterResults performFiltering(CharSequence prefix) { + FilterResults results = new FilterResults(); + + if (prefix == null || prefix.length() == 0) { + results.values = originalData; + results.count = originalData.size(); + } else { + String prefixString = prefix.toString().toLowerCase(); + + final ArrayList<BitmessageAddress> newValues = new ArrayList<>(); + + for (int i = 0; i < originalData.size(); i++) { + final BitmessageAddress value = originalData.get(i); + + // First match against the whole, non-splitted value + if (value.getAlias() != null) { + String alias = value.getAlias().toLowerCase(); + if (alias.startsWith(prefixString)) { + newValues.add(value); + } else { + final String[] words = alias.split(" "); + + for (String word : words) { + if (word.startsWith(prefixString)) { + newValues.add(value); + break; + } + } + } + } else { + String address = value.getAddress().toLowerCase(); + if (address.contains(prefixString)) { + newValues.add(value); + } + } + } + + results.values = newValues; + results.count = newValues.size(); + } + + return results; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + //noinspection unchecked + data = (List<BitmessageAddress>) results.values; + if (results.count > 0) { + notifyDataSetChanged(); + } else { + notifyDataSetInvalidated(); + } + } + } +} diff --git a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java index e52eb95..55f54d5 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java @@ -1,6 +1,7 @@ package ch.dissem.apps.abit.service; import android.app.Service; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; @@ -8,6 +9,7 @@ import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -129,6 +131,9 @@ public class BitmessageService extends Service { String message = msg.getData().getString(DATA_FIELD_MESSAGE); bmc.send((BitmessageAddress) identity, (BitmessageAddress) address, subject, message); + } else { + Context ctx = service.get(); + Toast.makeText(ctx, "Could not send", Toast.LENGTH_LONG); } break; } diff --git a/app/src/main/res/layout/contact_row.xml b/app/src/main/res/layout/contact_row.xml new file mode 100644 index 0000000..b71f67e --- /dev/null +++ b/app/src/main/res/layout/contact_row.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright 2015 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. + --> + +<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="wrap_content"> + + <ImageView + android:id="@+id/avatar" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_alignParentTop="true" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:src="@color/accent" + android:layout_margin="16dp"/> + + <TextView + android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Name" + android:lines="1" + android:ellipsize="end" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_alignTop="@+id/avatar" + android:layout_toRightOf="@+id/avatar" + android:layout_toEndOf="@+id/avatar" + android:paddingTop="0dp" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:paddingBottom="0dp" + android:textStyle="bold" + /> + + <TextView + android:id="@+id/address" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="BM-2cW0000000000000000000000000000000" + android:lines="1" + android:ellipsize="marquee" + android:textAppearance="?android:attr/textAppearanceSmall" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:layout_alignBottom="@+id/avatar" + android:layout_toRightOf="@+id/avatar" + android:layout_toEndOf="@+id/avatar"/> + +</RelativeLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_compose_message.xml b/app/src/main/res/layout/fragment_compose_message.xml index e3e0887..72c23c7 100644 --- a/app/src/main/res/layout/fragment_compose_message.xml +++ b/app/src/main/res/layout/fragment_compose_message.xml @@ -1,51 +1,47 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:fitsSystemWindows="true"> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true" + android:orientation="vertical"> <android.support.design.widget.TextInputLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="4dp"> + + <AutoCompleteTextView + android:id="@+id/recipient" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="4dp"> - - <EditText - android:id="@+id/recipient" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="textNoSuggestions" - android:singleLine="true" - android:hint="@string/to"/> + android:hint="@string/to" + android:inputType="textNoSuggestions" + android:singleLine="true" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_width="match_parent" + android:layout_height="wrap_content"> <EditText - android:id="@+id/subject" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="textEmailSubject" - android:textAppearance="?android:attr/textAppearanceLarge" - android:hint="@string/subject"/> + android:id="@+id/subject" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/subject" + android:inputType="textEmailSubject" + android:textAppearance="?android:attr/textAppearanceLarge" /> </android.support.design.widget.TextInputLayout> - <ScrollView - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1"> - - <EditText - android:id="@+id/body" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="textMultiLine"/> - - </ScrollView> + <EditText + android:id="@+id/body" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:hint="@string/compose_body_hint" + android:inputType="textMultiLine|textCapSentences" + android:gravity="top" + android:isScrollContainer="true" /> </LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_subscription_detail.xml b/app/src/main/res/layout/fragment_contact_detail.xml similarity index 98% rename from app/src/main/res/layout/fragment_subscription_detail.xml rename to app/src/main/res/layout/fragment_contact_detail.xml index 16c3c9b..79bb54a 100644 --- a/app/src/main/res/layout/fragment_subscription_detail.xml +++ b/app/src/main/res/layout/fragment_contact_detail.xml @@ -70,7 +70,7 @@ <Switch android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/enabled" + android:text="@string/subscribed" android:id="@+id/active" android:paddingTop="16dp" android:paddingLeft="16dp" diff --git a/app/src/main/res/layout/fragment_subscribtions.xml b/app/src/main/res/layout/fragment_contact_list.xml similarity index 100% rename from app/src/main/res/layout/fragment_subscribtions.xml rename to app/src/main/res/layout/fragment_contact_list.xml diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7020bf7..da9a684 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -46,4 +46,7 @@ <string name="proof_of_work_title">Proof of Work</string> <string name="error_invalid_sync_host">Synchronisation fehlgeschlagen: der vertrauenswürdige Knoten konnte nicht erreicht werden.</string> <string name="error_invalid_sync_port">Ungültiger Port in den Synchronisationseinstellungen: %s</string> + <string name="compose_body_hint">Nachricht schreiben</string> + <string name="contacts_and_subscriptions">Kontakte</string> + <string name="subscribed">Abonniert</string> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ed1cd40..4ca446a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -46,4 +46,7 @@ <string name="proof_of_work_text">Warning: This might heat your device until the battery\'s dead.</string> <string name="error_invalid_sync_port">Invalid port in synchronization settings: %s</string> <string name="error_invalid_sync_host">Synchronization failed: Trusted node could not be reached.</string> + <string name="compose_body_hint">Write message</string> + <string name="contacts_and_subscriptions">Contacts</string> + <string name="subscribed">Subscribed</string> </resources>