aboutsummaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/AndroidManifest.xml17
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationFragment.java87
-rw-r--r--src/main/java/de/pixart/messenger/ui/RecordingActivity.java159
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java5
-rw-r--r--src/main/java/de/pixart/messenger/utils/ThemeHelper.java15
-rw-r--r--src/main/res/layout/activity_recording.xml91
-rw-r--r--src/main/res/values/attrs.xml1
-rw-r--r--src/main/res/values/strings.xml1
-rw-r--r--src/main/res/values/styles.xml6
-rw-r--r--src/main/res/values/themes.xml45
10 files changed, 224 insertions, 203 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index d4f7361ea..9f9787bf4 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -223,23 +223,10 @@
<activity
android:name=".ui.RecordingActivity"
android:configChanges="orientation|screenSize"
- android:label="@string/app_name"
- android:theme="@style/ConversationsDialog">
- <intent-filter>
- <action android:name="android.provider.MediaStore.RECORD_SOUND" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
+ android:theme="@style/ConversationsTheme.Dialog" />
<activity
android:name=".ui.ShareLocationActivity"
- android:label="@string/share_location"
- android:parentActivityName=".ui.ConversationsActivity">
- <intent-filter>
- <action android:name="de.pixart.messenger.location.request" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
+ android:label="@string/share_location" />
<activity
android:name=".ui.ShowLocationActivity"
android:label="@string/show_location">
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
index cad1beb44..def3c00f6 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
@@ -304,7 +304,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
return false;
}
}
- if (hasStoragePermission(REQUEST_ADD_EDITOR_CONTENT)) {
+ if (hasPermissions(REQUEST_ADD_EDITOR_CONTENT, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
attachImageToConversation(inputContentInfo.getContentUri());
} else {
mPendingEditorContent = inputContentInfo.getContentUri();
@@ -1561,22 +1561,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
public void attachFile(final int attachmentChoice) {
- if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_FROM_CAMERA) {
- if (!hasStorageAndCameraPermission(attachmentChoice)) {
- return;
- }
- } else if (attachmentChoice != ATTACHMENT_CHOICE_LOCATION) {
- if (!Config.ONLY_INTERNAL_STORAGE && !hasStoragePermission(attachmentChoice)) {
+ if (attachmentChoice == ATTACHMENT_CHOICE_RECORD_VOICE) {
+ if (!hasPermissions(attachmentChoice, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO)) {
return;
}
- }
- if (attachmentChoice == ATTACHMENT_CHOICE_RECORD_VOICE) {
- if (!activity.hasMicPermission(attachmentChoice)) {
+ } else if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_FROM_CAMERA) {
+ if (!hasPermissions(attachmentChoice, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)) {
return;
}
- }
- if (attachmentChoice == ATTACHMENT_CHOICE_LOCATION) {
- if (!activity.hasLocationPermission(attachmentChoice)) {
+ } else if (attachmentChoice != ATTACHMENT_CHOICE_LOCATION) {
+ if (!hasPermissions(attachmentChoice, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
return;
}
}
@@ -1654,7 +1648,10 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
} else {
@StringRes int res;
- if (Manifest.permission.CAMERA.equals(getFirstDenied(grantResults, permissions))) {
+ String firstDenied = getFirstDenied(grantResults, permissions);
+ if (Manifest.permission.RECORD_AUDIO.equals(firstDenied)) {
+ res = R.string.no_microphone_permission;
+ } else if (Manifest.permission.CAMERA.equals(firstDenied)) {
res = R.string.no_camera_permission;
} else {
res = R.string.no_storage_permission;
@@ -1665,7 +1662,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
public void startDownloadable(Message message) {
- if (!Config.ONLY_INTERNAL_STORAGE && !hasStoragePermission(REQUEST_START_DOWNLOAD)) {
+ if (!hasPermissions(REQUEST_START_DOWNLOAD, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
this.mPendingDownloadableMessage = message;
return;
}
@@ -1684,26 +1681,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
}
- private boolean hasStorageAndCameraPermission(int requestCode) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- List<String> missingPermissions = new ArrayList<>();
- if (!Config.ONLY_INTERNAL_STORAGE && activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- missingPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
- }
- if (activity.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
- missingPermissions.add(Manifest.permission.CAMERA);
- }
- if (missingPermissions.size() == 0) {
- return true;
- } else {
- requestPermissions(missingPermissions.toArray(new String[missingPermissions.size()]), requestCode);
- return false;
- }
- } else {
- return true;
- }
- }
-
@SuppressLint("InflateParams")
protected void clearHistoryDialog(final Conversation conversation) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
@@ -1728,13 +1705,22 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
builder.create().show();
}
- private boolean hasStoragePermission(int requestCode) {
+ private boolean hasPermissions(int requestCode, String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
- return false;
- } else {
+ final List<String> missingPermissions = new ArrayList<>();
+ for (String permission : permissions) {
+ if (Config.ONLY_INTERNAL_STORAGE && permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ continue;
+ }
+ if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ missingPermissions.add(permission);
+ }
+ }
+ if (missingPermissions.size() == 0) {
return true;
+ } else {
+ requestPermissions(missingPermissions.toArray(new String[missingPermissions.size()]), requestCode);
+ return false;
}
} else {
return true;
@@ -1747,7 +1733,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
final PresenceSelector.OnPresenceSelected callback = () -> {
final Intent intent = new Intent();
boolean chooser = false;
- String fallbackPackageId = null;
switch (attachmentChoice) {
case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
intent.setAction(Intent.ACTION_GET_CONTENT);
@@ -1807,8 +1792,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
} else {
startActivityForResult(intent, attachmentChoice);
}
- } else if (fallbackPackageId != null) {
- startActivity(getInstallApkIntent(fallbackPackageId));
}
};
if (account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) {
@@ -1821,26 +1804,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
}
- private Intent getInstallApkIntent(final String packageId) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse("market://details?id=" + packageId));
- if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
- return intent;
- } else {
- intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId));
- return intent;
- }
- }
-
@Override
public void onResume() {
- new Handler().post(() -> {
- final Activity activity = getActivity();
- if (activity == null) {
- return;
- }
- getActivity().invalidateOptionsMenu();
- });
super.onResume();
binding.messagesView.post(this::fireReadEvent);
}
diff --git a/src/main/java/de/pixart/messenger/ui/RecordingActivity.java b/src/main/java/de/pixart/messenger/ui/RecordingActivity.java
index b49566c27..545acd197 100644
--- a/src/main/java/de/pixart/messenger/ui/RecordingActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/RecordingActivity.java
@@ -1,41 +1,40 @@
package de.pixart.messenger.ui;
+import android.annotation.SuppressLint;
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
+import android.databinding.DataBindingUtil;
import android.media.MediaRecorder;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
+import android.os.FileObserver;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
+import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
+import de.pixart.messenger.databinding.ActivityRecordingBinding;
import de.pixart.messenger.persistance.FileBackend;
+import de.pixart.messenger.utils.ThemeHelper;
-public class RecordingActivity extends XmppActivity implements View.OnClickListener {
+public class RecordingActivity extends Activity implements View.OnClickListener {
- private TextView mTimerTextView;
- private Button mCancelButton;
- private Button mStopButton;
+ private ActivityRecordingBinding binding;
private MediaRecorder mRecorder;
private long mStartTime = 0;
- private int[] amplitudes = new int[100];
- private int i = 0;
-
private Handler mHandler = new Handler();
private Runnable mTickExecutor = new Runnable() {
@Override
@@ -44,38 +43,28 @@ public class RecordingActivity extends XmppActivity implements View.OnClickListe
mHandler.postDelayed(mTickExecutor, 100);
}
};
+
private File mOutputFile;
+ private boolean mShouldFinishAfterWrite = false;
+
+ private FileObserver mFileObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
+ setTheme(ThemeHelper.findDialog(this));
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_recording);
- this.mTheme = findTheme();
- setTheme(this.mTheme);
- this.mTimerTextView = this.findViewById(R.id.timer);
- this.mCancelButton = this.findViewById(R.id.cancel_button);
- this.mCancelButton.setOnClickListener(this);
- this.mStopButton = this.findViewById(R.id.share_button);
- this.mStopButton.setOnClickListener(this);
+ this.binding = DataBindingUtil.setContentView(this,R.layout.activity_recording);
+ this.binding.cancelButton.setOnClickListener(this);
+ this.binding.shareButton.setOnClickListener(this);
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- this.setTitle(R.string.attach_record_voice);
- }
-
- @Override
- protected void refreshUiReal() {
-
}
@Override
protected void onStart() {
super.onStart();
- this.mTheme = findTheme();
- setTheme(this.mTheme);
- Log.d(Config.LOGTAG, "output: " + getOutputFile());
if (!startRecording()) {
- mStopButton.setEnabled(false);
- mStopButton.setTextColor(0x8a000000);
+ this.binding.shareButton.setEnabled(false);
Toast.makeText(this, R.string.unable_to_start_recording, Toast.LENGTH_SHORT).show();
}
}
@@ -84,29 +73,22 @@ public class RecordingActivity extends XmppActivity implements View.OnClickListe
protected void onStop() {
super.onStop();
if (mRecorder != null) {
+ mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
}
- }
-
- @Override
- void onBackendConnected() {
-
+ if (mFileObserver != null) {
+ mFileObserver.stopWatching();
+ }
}
private boolean startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
- mRecorder.setAudioEncodingBitRate(48000);
- } else {
- mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
- mRecorder.setAudioEncodingBitRate(48000);
- }
- mRecorder.setAudioSamplingRate(48000);
- mOutputFile = getOutputFile();
- mOutputFile.getParentFile().mkdirs();
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ mRecorder.setAudioEncodingBitRate(48000);
+ mRecorder.setAudioSamplingRate(16000);
+ setupOutputFile();
mRecorder.setOutputFile(mOutputFile.getAbsolutePath());
try {
@@ -114,79 +96,96 @@ public class RecordingActivity extends XmppActivity implements View.OnClickListe
mRecorder.start();
mStartTime = SystemClock.elapsedRealtime();
mHandler.postDelayed(mTickExecutor, 100);
- Log.d(Config.LOGTAG, "started recording to " + mOutputFile.getAbsolutePath());
+ Log.d("Voice Recorder", "started recording to " + mOutputFile.getAbsolutePath());
return true;
} catch (Exception e) {
- Log.e(Config.LOGTAG, "prepare() failed " + e.getMessage());
+ Log.e("Voice Recorder", "prepare() failed " + e.getMessage());
return false;
}
}
protected void stopRecording(boolean saveFile) {
- mRecorder.stop();
+ mShouldFinishAfterWrite = saveFile;
+ try {
+ mRecorder.stop();
+ } catch (RuntimeException stopException) {
+ //handle cleanup here
+ }
mRecorder.release();
mRecorder = null;
mStartTime = 0;
- mHandler.removeCallbacks(mTickExecutor);
if (!saveFile && mOutputFile != null) {
- mOutputFile.delete();
+ if (mOutputFile.delete()) {
+ Log.d(Config.LOGTAG,"deleted canceled recording");
+ }
}
}
- private File getOutputFile() {
+ private static File generateOutputFilename(Context context) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
return new File(FileBackend.getConversationsDirectory("Audios", true) + "/"
+ dateFormat.format(new Date())
+ ".m4a");
}
+ private void setupOutputFile() {
+ mOutputFile = generateOutputFilename(this);
+ File parentDirectory = mOutputFile.getParentFile();
+ if (parentDirectory.mkdirs()) {
+ Log.d(Config.LOGTAG, "created " + parentDirectory.getAbsolutePath());
+ }
+ File noMedia = new File(parentDirectory, ".nomedia");
+ if (!noMedia.exists()) {
+ try {
+ if (noMedia.createNewFile()) {
+ Log.d(Config.LOGTAG, "created nomedia file in " + parentDirectory.getAbsolutePath());
+ }
+ } catch (IOException e) {
+ Log.d(Config.LOGTAG, "unable to create nomedia file in " + parentDirectory.getAbsolutePath(), e);
+ }
+ }
+ setupFileObserver(parentDirectory);
+ }
+
+ private void setupFileObserver(File directory) {
+ mFileObserver = new FileObserver(directory.getAbsolutePath()) {
+ @Override
+ public void onEvent(int event, String s) {
+ if (s != null && s.equals(mOutputFile.getName()) && event == FileObserver.CLOSE_WRITE) {
+ if (mShouldFinishAfterWrite) {
+ setResult(Activity.RESULT_OK, new Intent().setData(Uri.fromFile(mOutputFile)));
+ finish();
+ }
+ }
+ }
+ };
+ mFileObserver.startWatching();
+ }
+
+ @SuppressLint("SetTextI18n")
private void tick() {
long time = (mStartTime < 0) ? 0 : (SystemClock.elapsedRealtime() - mStartTime);
int minutes = (int) (time / 60000);
int seconds = (int) (time / 1000) % 60;
int milliseconds = (int) (time / 100) % 10;
- mTimerTextView.setText(minutes + ":" + (seconds < 10 ? "0" + seconds : seconds) + "." + milliseconds);
- if (mRecorder != null) {
- amplitudes[i] = mRecorder.getMaxAmplitude();
- //Log.d(Config.LOGTAG,"amplitude: "+(amplitudes[i] * 100 / 32767));
- if (i >= amplitudes.length - 1) {
- i = 0;
- } else {
- ++i;
- }
- }
+ this.binding.timer.setText(minutes + ":" + (seconds < 10 ? "0" + seconds : seconds) + "." + milliseconds);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.cancel_button:
+ mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
setResult(RESULT_CANCELED);
finish();
break;
case R.id.share_button:
- stopRecording(true);
- Uri uri = Uri.parse("file://" + mOutputFile.getAbsolutePath());
- Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- scanIntent.setData(uri);
- sendBroadcast(scanIntent);
- setResult(Activity.RESULT_OK, new Intent().setData(uri));
- finish();
+ this.binding.shareButton.setEnabled(false);
+ this.binding.shareButton.setText(R.string.please_wait);
+ mHandler.removeCallbacks(mTickExecutor);
+ mHandler.postDelayed(() -> stopRecording(true), 500);
break;
}
}
-
- public boolean isDarkTheme() {
- return this.mTheme == R.style.ConversationsDialog_Dark;
- }
-
- protected int findTheme() {
- final Boolean dark = getPreferences().getString(SettingsActivity.THEME, getResources().getString(R.string.theme)).equals("dark");
- if (dark) {
- return R.style.ConversationsDialog_Dark;
- } else {
- return R.style.ConversationsDialog;
- }
- }
} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java b/src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java
index 28b8cd42e..c56f27ebf 100644
--- a/src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java
+++ b/src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java
@@ -33,7 +33,6 @@ import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
-import android.os.Build;
import java.util.ArrayList;
import java.util.List;
@@ -45,8 +44,8 @@ public class AttachmentTool {
if (intent == null) {
return uris;
}
- Uri uri = intent.getData();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) {
+ final Uri uri = intent.getData();
+ if (uri == null) {
final ClipData clipData = intent.getClipData();
if (clipData != null) {
for (int i = 0; i < clipData.getItemCount(); ++i) {
diff --git a/src/main/java/de/pixart/messenger/utils/ThemeHelper.java b/src/main/java/de/pixart/messenger/utils/ThemeHelper.java
index 3568a488a..27a48f069 100644
--- a/src/main/java/de/pixart/messenger/utils/ThemeHelper.java
+++ b/src/main/java/de/pixart/messenger/utils/ThemeHelper.java
@@ -59,6 +59,21 @@ public class ThemeHelper {
}
}
+ public static int findDialog(Context context) {
+ final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ final Resources resources = context.getResources();
+ final boolean dark = sharedPreferences.getString(SettingsActivity.THEME, resources.getString(R.string.theme)).equals("dark");
+ final String fontSize = sharedPreferences.getString("font_size", resources.getString(R.string.default_font_size));
+ switch (fontSize) {
+ case "medium":
+ return dark ? R.style.ConversationsTheme_Dark_Dialog_Medium : R.style.ConversationsTheme_Dialog_Medium;
+ case "large":
+ return dark ? R.style.ConversationsTheme_Dark_Dialog_Large : R.style.ConversationsTheme_Dialog_Large;
+ default:
+ return dark ? R.style.ConversationsTheme_Dark_Dialog: R.style.ConversationsTheme_Dialog;
+ }
+ }
+
public static boolean isDark(@StyleRes int id) {
switch (id) {
case R.style.ConversationsTheme_Dark:
diff --git a/src/main/res/layout/activity_recording.xml b/src/main/res/layout/activity_recording.xml
index c8f83b0e0..35097fef4 100644
--- a/src/main/res/layout/activity_recording.xml
+++ b/src/main/res/layout/activity_recording.xml
@@ -1,52 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?attr/color_background_primary">
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
- <LinearLayout
- android:id="@+id/button_bar"
- android:layout_width="fill_parent"
+ <RelativeLayout
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_below="@+id/timer">
+ android:background="?attr/color_background_primary">
- <Button
- android:id="@+id/cancel_button"
- style="@style/Widget.Conversations.Button.Borderless"
- android:layout_width="0dp"
+ <LinearLayout
+ android:id="@+id/button_bar"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/cancel"
- android:textColor="?attr/colorAccent" />
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/timer">
- <View
- android:layout_width="1dp"
- android:layout_height="fill_parent"
- android:layout_marginBottom="7dp"
- android:layout_marginTop="7dp"
- android:textColor="?attr/colorAccent" />
+ <Button
+ android:id="@+id/cancel_button"
+ style="@style/Widget.Conversations.Button.Borderless"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/cancel"
+ android:textColor="?attr/colorAccent" />
- <Button
- android:id="@+id/share_button"
- style="@style/Widget.Conversations.Button.Borderless"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/share"
- android:textColor="?attr/colorAccent" />
- </LinearLayout>
+ <View
+ android:layout_width="1dp"
+ android:layout_height="fill_parent"
+ android:layout_marginBottom="7dp"
+ android:layout_marginTop="7dp"
+ android:textColor="?attr/colorAccent" />
- <TextView
- android:id="@+id/timer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:text="0:00.0"
- android:textColor="?attr/colorAccent"
- android:textSize="50sp"
- android:textStyle="bold"
- android:typeface="monospace" />
-</RelativeLayout> \ No newline at end of file
+ <Button
+ android:id="@+id/share_button"
+ style="@style/Widget.Conversations.Button.Borderless"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/share"
+ android:textColor="?attr/colorAccent" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/timer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:text="0:00.0"
+ android:textColor="?attr/colorAccent"
+ android:textSize="50sp"
+ android:textStyle="bold"
+ android:typeface="monospace" />
+ </RelativeLayout>
+</layout> \ No newline at end of file
diff --git a/src/main/res/values/attrs.xml b/src/main/res/values/attrs.xml
index f6c2e5fed..6cb9893ea 100644
--- a/src/main/res/values/attrs.xml
+++ b/src/main/res/values/attrs.xml
@@ -7,6 +7,7 @@
<attr name="TextSizeSubhead" format="dimension" />
<attr name="TextSizeBody1" format="dimension" />
<attr name="TextSizeBody2" format="dimension" />
+ <attr name="TextSizeDisplay2" format="dimension"/>
<attr name="TextSizeInput" format="dimension" />
<attr name="TextSeparation" format="dimension" />
<attr name="TextSizeBody" format="dimension" />
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 3b176f4f3..585e87a4b 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -779,4 +779,5 @@
<string name="large">Large</string>
<string name="create_shortcut">Create Shortcut</string>
<string name="not_encrypted_for_this_device">Message was not encrypted for this device.</string>
+ <string name="no_microphone_permission">Conversations needs access to the microphone</string>
</resources>
diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml
index e3038c62e..e67e4db1e 100644
--- a/src/main/res/values/styles.xml
+++ b/src/main/res/values/styles.xml
@@ -1,5 +1,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
+ <style name="TextAppearance.Conversations.Display2.Monospace" parent="TextAppearance.AppCompat.Display2">
+ <item name="android:textSize">?TextSizeDisplay2</item>
+ <item name="android:fontFamily" tools:targetApi="jelly_bean">monospace</item>
+ <item name="android:typeface">monospace</item>
+ </style>
+
<style name="TextAppearance.Conversations.Title" parent="TextAppearance.AppCompat.Title">
<item name="android:textSize">?TextSizeTitle</item>
</style>
diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml
index 0eb408e09..2860b5c59 100644
--- a/src/main/res/values/themes.xml
+++ b/src/main/res/values/themes.xml
@@ -247,6 +247,7 @@
<item name="TextSizeCaption">12sp</item>
<item name="TextSizeBody1">14sp</item>
<item name="TextSizeBody2">14sp</item>
+ <item name="TextSizeDisplay2">45sp</item>
<item name="TextSizeSubhead">16sp</item>
<item name="TextSizeTitle">20sp</item>
<item name="TextSizeInput">16sp</item>
@@ -270,6 +271,7 @@
<item name="TextSizeCaption">12sp</item>
<item name="TextSizeBody1">14sp</item>
<item name="TextSizeBody2">14sp</item>
+ <item name="TextSizeDisplay2">45sp</item>
<item name="TextSizeSubhead">16sp</item>
<item name="TextSizeTitle">20sp</item>
<item name="TextSizeInput">16sp</item>
@@ -286,6 +288,49 @@
<item name="android:background">@color/grey900</item>
</style>
+
+ <style name="ConversationsTheme.Dialog" parent="@style/Theme.AppCompat.Light.Dialog">
+ <item name="colorPrimary">@color/primary</item>
+ <item name="colorPrimaryDark">@color/primary_dark</item>
+ <item name="colorAccent">@color/accent</item>
+ <item name="color_background_primary">@color/grey50</item>
+ <item name="divider">@color/black12</item>
+ <item name="TextSizeBody2">14sp</item>
+ <item name="TextSizeDisplay2">45sp</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
+ <style name="ConversationsTheme.Dark.Dialog" parent="@style/Theme.AppCompat.Dialog">
+ <item name="colorPrimary">@color/primary</item>
+ <item name="colorPrimaryDark">@color/primary_dark</item>
+ <item name="colorAccent">@color/accent</item>
+ <item name="color_background_primary">@color/grey800</item>
+ <item name="divider">@color/white12</item>
+ <item name="TextSizeBody2">14sp</item>
+ <item name="TextSizeDisplay2">45sp</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
+ <style name="ConversationsTheme.Dialog.Medium" parent="ConversationsTheme.Dialog">
+ <item name="TextSizeBody2">16sp</item>
+ <item name="TextSizeDisplay2">51sp</item>
+ </style>
+
+ <style name="ConversationsTheme.Dark.Dialog.Medium" parent="ConversationsTheme.Dark.Dialog">
+ <item name="TextSizeBody2">16sp</item>
+ <item name="TextSizeDisplay2">51sp</item>
+ </style>
+
+ <style name="ConversationsTheme.Dialog.Large" parent="ConversationsTheme.Dialog">
+ <item name="TextSizeBody2">18sp</item>
+ <item name="TextSizeDisplay2">56sp</item>
+ </style>
+
+ <style name="ConversationsTheme.Dark.Dialog.Large" parent="ConversationsTheme.Dark.Dialog">
+ <item name="TextSizeBody2">18sp</item>
+ <item name="TextSizeTitle">56sp</item>
+ </style>
+
<style name="ConversationsTheme.FullScreen" parent="@style/Theme.AppCompat.Light">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primary_dark</item>