From 576d769f46d91d789f95813df3cd4925f48fb7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Turnel?= Date: Mon, 26 Nov 2018 15:19:34 +0100 Subject: [PATCH] Add recordings list view --- .../java/org/linphone/LinphoneActivity.java | 10 +- .../fragments/FragmentsAvailable.java | 3 +- .../org/linphone/recording/Recording.java | 152 ++++++++++ .../linphone/recording/RecordingAdapter.java | 275 ++++++++++++++++++ .../recording/RecordingListFragment.java | 192 ++++++++++++ .../linphone/recording/RecordingListener.java | 26 ++ .../menu_recordings.png | Bin .../options_rec_default.png | Bin .../options_rec_selected.png | Bin .../main/res/drawable-xhdpi/record_pause.png | Bin 0 -> 5820 bytes .../main/res/drawable-xhdpi/record_play.png | Bin 0 -> 7888 bytes .../recording.png | Bin app/src/main/res/layout/recording_cell.xml | 141 +++++++++ app/src/main/res/layout/recordings.xml | 67 +++++ app/src/main/res/values/strings.xml | 1 + 15 files changed, 863 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/org/linphone/recording/Recording.java create mode 100644 app/src/main/java/org/linphone/recording/RecordingAdapter.java create mode 100644 app/src/main/java/org/linphone/recording/RecordingListFragment.java create mode 100644 app/src/main/java/org/linphone/recording/RecordingListener.java rename app/src/main/res/{drawable => drawable-xhdpi}/menu_recordings.png (100%) rename app/src/main/res/{drawable => drawable-xhdpi}/options_rec_default.png (100%) rename app/src/main/res/{drawable => drawable-xhdpi}/options_rec_selected.png (100%) create mode 100644 app/src/main/res/drawable-xhdpi/record_pause.png create mode 100644 app/src/main/res/drawable-xhdpi/record_play.png rename app/src/main/res/{drawable => drawable-xhdpi}/recording.png (100%) create mode 100644 app/src/main/res/layout/recording_cell.xml create mode 100644 app/src/main/res/layout/recordings.xml diff --git a/app/src/main/java/org/linphone/LinphoneActivity.java b/app/src/main/java/org/linphone/LinphoneActivity.java index 4de17425a..ab94f84e1 100644 --- a/app/src/main/java/org/linphone/LinphoneActivity.java +++ b/app/src/main/java/org/linphone/LinphoneActivity.java @@ -110,6 +110,7 @@ import org.linphone.purchase.InAppPurchaseActivity; import org.linphone.views.AddressText; import org.linphone.utils.LinphoneGenericActivity; import org.linphone.utils.LinphoneUtils; +import org.linphone.recording.RecordingListFragment; import org.linphone.xmlrpc.XmlRpcHelper; import org.linphone.xmlrpc.XmlRpcListenerBase; @@ -135,7 +136,7 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick private StatusFragment statusFragment; private TextView missedCalls, missedChats; private RelativeLayout contacts, history, dialer, chat; - private View contacts_selected, history_selected, dialer_selected, chat_selected; + private View contacts_selected, history_selected, dialer_selected, chat_selected, record_selected; private LinearLayout mTopBar; private TextView mTopBarTitle; private ImageView cancel; @@ -428,6 +429,9 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick case CONTACT_DEVICES: fragment = new DevicesFragment(); break; + case RECORDING_LIST: + fragment = new RecordingListFragment(); + break; default: break; } @@ -638,7 +642,7 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick } public void displayRecordings() { - + changeCurrentFragment(FragmentsAvailable.RECORDING_LIST, null); } public void displayContactsForEdition(String sipAddress, String displayName) { @@ -1634,7 +1638,7 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick LinphoneActivity.instance().displayInapp(); } } - if (sideMenuItemList.getAdapter().getItem(i).toString().equals(R.string.menu_recordings)) { + if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_recordings))) { LinphoneActivity.instance().displayRecordings(); } openOrCloseSideMenu(false); diff --git a/app/src/main/java/org/linphone/fragments/FragmentsAvailable.java b/app/src/main/java/org/linphone/fragments/FragmentsAvailable.java index d59fc5df0..9ed1af3da 100644 --- a/app/src/main/java/org/linphone/fragments/FragmentsAvailable.java +++ b/app/src/main/java/org/linphone/fragments/FragmentsAvailable.java @@ -37,7 +37,8 @@ public enum FragmentsAvailable { INFO_GROUP_CHAT, GROUP_CHAT, MESSAGE_IMDN, - CONTACT_DEVICES; + CONTACT_DEVICES, + RECORDING_LIST; public boolean shouldAddItselfToTheRightOf(FragmentsAvailable fragment) { switch (this) { diff --git a/app/src/main/java/org/linphone/recording/Recording.java b/app/src/main/java/org/linphone/recording/Recording.java new file mode 100644 index 000000000..588360772 --- /dev/null +++ b/app/src/main/java/org/linphone/recording/Recording.java @@ -0,0 +1,152 @@ +package org.linphone.recording; + +/* +Recording.java +Copyright (C) 2018 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.annotation.SuppressLint; +import android.support.annotation.NonNull; + +import org.linphone.LinphoneManager; +import org.linphone.core.Player; +import org.linphone.core.PlayerListener; +import org.linphone.mediastream.Log; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Recording implements PlayerListener, Comparable { + private String recordPath, name; + private Date recordDate; + private Player player; + private RecordingListener listener; + private Timer timer; + private TimerTask updateCurrentPositionTimer; + + private static final Pattern mRecordPattern = Pattern.compile(".*/(.*)_(\\d{2}-\\d{2}-\\d{4}-\\d{2}-\\d{2}-\\d{2})\\..*"); + + @SuppressLint("SimpleDateFormat") + public Recording(String recordPath) { + this.recordPath = recordPath; + + Matcher m = mRecordPattern.matcher(recordPath); + if (m.matches()) { + name = m.group(1); + + try { + recordDate = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss").parse(m.group(2)); + } catch (ParseException e) { + Log.e(e); + } + } + + timer = new Timer(); + updateCurrentPositionTimer = new TimerTask() { + @Override + public void run() { + if (listener != null) listener.currentPositionChanged(getCurrentPosition()); + } + }; + + player = LinphoneManager.getLc().createLocalPlayer(null, null, null); + player.setListener(this); + player.open(recordPath); + } + + public String getRecordPath() { + return recordPath; + } + + public String getName() { + return name; + } + + public Date getRecordDate() { + return recordDate; + } + + public boolean isClosed() { + return player.getState() == Player.State.Closed; + } + + public void play() { + player.start(); + //timer.scheduleAtFixedRate(updateCurrentPositionTimer, 0, 1000); + } + + public boolean isPlaying() { + return player.getState() == Player.State.Playing; + } + + public void pause() { + if (!isClosed()) { + player.pause(); + + timer.cancel(); + timer.purge(); + } + } + + public boolean isPaused() { + return player.getState() == Player.State.Paused; + } + + public void seek(int i) { + if (!isClosed()) player.seek(i); + } + + public int getCurrentPosition() { + return player.getCurrentPosition(); + } + + public int getDuration() { + return player.getDuration(); + } + + public void close() { + player.close(); + } + + public void setRecordingListener(RecordingListener listener) { + this.listener = listener; + } + + @Override + public void onEofReached(Player player) { + if (listener != null) listener.endOfRecordReached(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Recording) { + Recording r = (Recording) o; + return recordPath.equals(r.getRecordPath()); + } + return false; + } + + @Override + public int compareTo(@NonNull Recording o) { + return -recordDate.compareTo(o.getRecordDate()); + } +} diff --git a/app/src/main/java/org/linphone/recording/RecordingAdapter.java b/app/src/main/java/org/linphone/recording/RecordingAdapter.java new file mode 100644 index 000000000..5222b3ef0 --- /dev/null +++ b/app/src/main/java/org/linphone/recording/RecordingAdapter.java @@ -0,0 +1,275 @@ +package org.linphone.recording; + +/* +RecordingAdapter.java +Copyright (C) 2018 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.annotation.SuppressLint; +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import org.linphone.R; +import org.linphone.mediastream.Log; +import org.linphone.ui.SelectableAdapter; +import org.linphone.ui.SelectableHelper; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +public class RecordingAdapter extends SelectableAdapter { + + public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { + public ImageView playButton; + public TextView name, date, currentPosition, duration; + public SeekBar progressionBar; + public CheckBox select; + public LinearLayout separator; + public TextView separatorText; + private RecordingAdapter.ViewHolder.ClickListener listener; + + public ViewHolder(View view, RecordingAdapter.ViewHolder.ClickListener listener) { + super(view); + + playButton = view.findViewById(R.id.record_play); + name = view.findViewById(R.id.record_name); + date = view.findViewById(R.id.record_date); + currentPosition = view.findViewById(R.id.record_current_time); + duration = view.findViewById(R.id.record_duration); + progressionBar = view.findViewById(R.id.record_progression_bar); + select = view.findViewById(R.id.delete); + separator = view.findViewById(R.id.separator); + separatorText = view.findViewById(R.id.separator_text); + + this.listener = listener; + view.setOnClickListener(this); + view.setOnLongClickListener(this); + } + + @Override + public void onClick(View view) { + if (listener != null) { + listener.onItemClicked(getAdapterPosition()); + } + } + + @Override + public boolean onLongClick(View view) { + if (listener != null) { + return listener.onItemLongClicked(getAdapterPosition()); + } + return false; + } + + public interface ClickListener { + void onItemClicked(int position); + + boolean onItemLongClicked(int position); + } + } + + private List recordings; + private Context context; + private RecordingAdapter.ViewHolder.ClickListener clickListener; + + public RecordingAdapter(Context context, List recordings, RecordingAdapter.ViewHolder.ClickListener listener, SelectableHelper helper) { + super(helper); + + this.recordings = recordings; + this.context = context; + this.clickListener = listener; + } + + @Override + public Object getItem(int position) { + return recordings.get(position); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recording_cell, viewGroup, false); + return new RecordingAdapter.ViewHolder(v, clickListener); + } + + @SuppressLint("SimpleDateFormat") + @Override + public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int i) { + final Recording record = recordings.get(i); + + viewHolder.name.setSelected(true); // For automated horizontal scrolling of long texts + + Calendar recordTime = Calendar.getInstance(); + recordTime.setTime(record.getRecordDate()); + viewHolder.separatorText.setText(DateToHumanDate(recordTime)); + viewHolder.select.setVisibility(isEditionEnabled() ? View.VISIBLE : View.GONE); + viewHolder.select.setChecked(isSelected(i)); + + if (i > 0) { + Recording previousRecord = recordings.get(i - 1); + Date previousRecordDate = previousRecord.getRecordDate(); + Calendar previousRecordTime = Calendar.getInstance(); + previousRecordTime.setTime(previousRecordDate); + + if (isSameDay(previousRecordTime, recordTime)) { + viewHolder.separator.setVisibility(View.GONE); + } else { + viewHolder.separator.setVisibility(View.VISIBLE); + } + } else { + viewHolder.separator.setVisibility(View.VISIBLE); + } + + if (record.isPlaying()) { + viewHolder.playButton.setImageResource(R.drawable.record_pause); + } else { + viewHolder.playButton.setImageResource(R.drawable.record_play); + } + viewHolder.playButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (record.isPaused()) { + record.play(); + viewHolder.playButton.setImageResource(R.drawable.record_pause); + } else { + record.pause(); + viewHolder.playButton.setImageResource(R.drawable.record_play); + } + } + }); + + viewHolder.name.setText(record.getName()); + viewHolder.date.setText(new SimpleDateFormat("HH:mm").format(record.getRecordDate())); + + int position = record.getCurrentPosition(); + viewHolder.currentPosition.setText(String.format("%02d:%02d", + TimeUnit.MILLISECONDS.toMinutes(position), + TimeUnit.MILLISECONDS.toSeconds(position) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(position)) + )); + //viewHolder.currentPosition.setText("00:00"); + + int duration = record.getDuration(); + viewHolder.duration.setText(String.format("%02d:%02d", + TimeUnit.MILLISECONDS.toMinutes(duration), + TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)) + )); + + viewHolder.progressionBar.setMax(100); + viewHolder.progressionBar.setProgress(0); + viewHolder.progressionBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + if (progress == 0) { + record.seek(0); + } else if (progress == seekBar.getMax()) { + if (record.isPlaying()) record.pause(); + record.seek(0); + seekBar.setProgress(0); + } else { + record.seek(progress); + + int currentPosition = record.getCurrentPosition(); + viewHolder.currentPosition.setText(String.format("%02d:%02d", + TimeUnit.MILLISECONDS.toMinutes(currentPosition), + TimeUnit.MILLISECONDS.toSeconds(currentPosition) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(currentPosition)) + )); + } + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } + }); + + record.setRecordingListener(new RecordingListener() { + @Override + public void currentPositionChanged(int currentPosition) { + viewHolder.currentPosition.setText(String.format("%02d:%02", + currentPosition % 60, + currentPosition - (currentPosition % 60) * 60, Locale.getDefault())); + viewHolder.progressionBar.setProgress(currentPosition); + } + + @Override + public void endOfRecordReached() { + record.pause(); + record.seek(0); + viewHolder.progressionBar.setProgress(0); + } + }); + } + + @Override + public int getItemCount() { + return recordings.size(); + } + + @SuppressLint("SimpleDateFormat") + private String DateToHumanDate(Calendar cal) { + SimpleDateFormat dateFormat; + if (isToday(cal)) { + return context.getString(R.string.today); + } else if (isYesterday(cal)) { + return context.getString(R.string.yesterday); + } else { + dateFormat = new SimpleDateFormat(context.getResources().getString(R.string.history_date_format)); + } + + return dateFormat.format(cal.getTime()); + } + + private boolean isSameDay(Calendar cal1, Calendar cal2) { + if (cal1 == null || cal2 == null) { + return false; + } + + return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && + cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && + cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); + } + + private boolean isToday(Calendar cal) { + return isSameDay(cal, Calendar.getInstance()); + } + + private boolean isYesterday(Calendar cal) { + Calendar yesterday = Calendar.getInstance(); + yesterday.roll(Calendar.DAY_OF_MONTH, -1); + return isSameDay(cal, yesterday); + } +} diff --git a/app/src/main/java/org/linphone/recording/RecordingListFragment.java b/app/src/main/java/org/linphone/recording/RecordingListFragment.java new file mode 100644 index 000000000..0a17aa3c7 --- /dev/null +++ b/app/src/main/java/org/linphone/recording/RecordingListFragment.java @@ -0,0 +1,192 @@ +package org.linphone.recording; + +/* +RecordingListFragment.java +Copyright (C) 2018 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.support.v7.widget.DividerItemDecoration; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.TextView; + +import org.linphone.LinphoneUtils; +import org.linphone.R; +import org.linphone.activities.LinphoneActivity; +import org.linphone.fragments.FragmentsAvailable; +import org.linphone.mediastream.Log; +import org.linphone.ui.SelectableHelper; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class RecordingListFragment extends Fragment implements View.OnClickListener, AdapterView.OnItemClickListener, RecordingAdapter.ViewHolder.ClickListener, SelectableHelper.DeleteListener { + private RecyclerView recordingList; + private List recordings; + private TextView noRecordings; + private RecordingAdapter recordingAdapter; + private LinearLayoutManager layoutManager; + private Context context; + private SelectableHelper selectableHelper; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.recordings, container, false); + + context = getActivity().getApplicationContext(); + selectableHelper = new SelectableHelper(view, this); + + recordingList = view.findViewById(R.id.recording_list); + noRecordings = view.findViewById(R.id.no_recordings); + + layoutManager = new LinearLayoutManager(context); + recordingList.setLayoutManager(layoutManager); + + //Divider between items + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recordingList.getContext(), + layoutManager.getOrientation()); + dividerItemDecoration.setDrawable(context.getResources().getDrawable(R.drawable.divider)); + recordingList.addItemDecoration(dividerItemDecoration); + + recordings = new ArrayList<>(); + + return view; + } + + private void hideRecordingListAndDisplayMessageIfEmpty() { + if (recordings == null || recordings.isEmpty()) { + noRecordings.setVisibility(View.VISIBLE); + recordingList.setVisibility(View.GONE); + } else { + noRecordings.setVisibility(View.GONE); + recordingList.setVisibility(View.VISIBLE); + } + } + + public void searchForRecordings() { + String recordingsDirectory = LinphoneUtils.getRecordingsDirectory(context); + File directory = new File(recordingsDirectory); + + if (directory.exists() && directory.isDirectory()) { + File[] existingRecordings = directory.listFiles(); + + for (File f : existingRecordings) { + boolean exists = false; + for(Recording r : recordings) { + if (r.getRecordPath().equals(f.getPath())) { + exists = true; + break; + } + } + + if (!exists) recordings.add(new Recording(f.getPath())); + } + + Collections.sort(recordings); + } + } + + @Override + public void onResume() { + super.onResume(); + + if (LinphoneActivity.isInstanciated()) { + LinphoneActivity.instance().selectMenu(FragmentsAvailable.RECORDING_LIST); + } + + searchForRecordings(); + + hideRecordingListAndDisplayMessageIfEmpty(); + recordingAdapter = new RecordingAdapter(getActivity().getApplicationContext(), recordings, this, selectableHelper); + recordingList.setAdapter(recordingAdapter); + selectableHelper.setAdapter(recordingAdapter); + selectableHelper.setDialogMessage(R.string.recordings_delete_dialog); + } + + @Override + public void onPause() { + super.onPause(); + + // Close all opened recordings + for (Recording r : recordings) { + if (!r.isClosed()) { + if (r.isPlaying()) r.pause(); + r.close(); + } + } + } + + @Override + public void onClick(View v) { + + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (recordingAdapter.isEditionEnabled()) { + Recording record = recordings.get(position); + recordings.remove(position); + + if (record.isPlaying()) record.pause(); + record.close(); + + File recordingFile = new File(record.getRecordPath()); + recordingFile.delete(); + } + } + + @Override + public void onItemClicked(int position) { + if (recordingAdapter.isEditionEnabled()) { + recordingAdapter.toggleSelection(position); + } + } + + @Override + public boolean onItemLongClicked(int position) { + if (!recordingAdapter.isEditionEnabled()) { + selectableHelper.enterEditionMode(); + } + recordingAdapter.toggleSelection(position); + return true; + } + + @Override + public void onDeleteSelection(Object[] objectsToDelete) { + int size = recordingAdapter.getSelectedItemCount(); + for (int i = 0; i < size; i++) { + Recording record = (Recording) objectsToDelete[i]; + recordings.remove(record); + + if (record.isPlaying()) record.pause(); + record.close(); + + File recordingFile = new File(record.getRecordPath()); + recordingFile.delete(); + } + } +} diff --git a/app/src/main/java/org/linphone/recording/RecordingListener.java b/app/src/main/java/org/linphone/recording/RecordingListener.java new file mode 100644 index 000000000..8853d8c14 --- /dev/null +++ b/app/src/main/java/org/linphone/recording/RecordingListener.java @@ -0,0 +1,26 @@ +package org.linphone.recording; + +/* +RecordingListener.java +Copyright (C) 2018 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +public interface RecordingListener { + void currentPositionChanged(int currentPosition); + + void endOfRecordReached(); +} diff --git a/app/src/main/res/drawable/menu_recordings.png b/app/src/main/res/drawable-xhdpi/menu_recordings.png similarity index 100% rename from app/src/main/res/drawable/menu_recordings.png rename to app/src/main/res/drawable-xhdpi/menu_recordings.png diff --git a/app/src/main/res/drawable/options_rec_default.png b/app/src/main/res/drawable-xhdpi/options_rec_default.png similarity index 100% rename from app/src/main/res/drawable/options_rec_default.png rename to app/src/main/res/drawable-xhdpi/options_rec_default.png diff --git a/app/src/main/res/drawable/options_rec_selected.png b/app/src/main/res/drawable-xhdpi/options_rec_selected.png similarity index 100% rename from app/src/main/res/drawable/options_rec_selected.png rename to app/src/main/res/drawable-xhdpi/options_rec_selected.png diff --git a/app/src/main/res/drawable-xhdpi/record_pause.png b/app/src/main/res/drawable-xhdpi/record_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..3b9311e43b9e8f5475e229ede9f97569c3710409 GIT binary patch literal 5820 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/record_play.png b/app/src/main/res/drawable-xhdpi/record_play.png new file mode 100644 index 0000000000000000000000000000000000000000..486dfb0de0dd04b85846f36e0ded1e764f828396 GIT binary patch literal 7888 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 Q2>c`Nb=Xt6>*#O)2f>lKasU7T literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/recording.png b/app/src/main/res/drawable-xhdpi/recording.png similarity index 100% rename from app/src/main/res/drawable/recording.png rename to app/src/main/res/drawable-xhdpi/recording.png diff --git a/app/src/main/res/layout/recording_cell.xml b/app/src/main/res/layout/recording_cell.xml new file mode 100644 index 000000000..f3a477de8 --- /dev/null +++ b/app/src/main/res/layout/recording_cell.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recordings.xml b/app/src/main/res/layout/recordings.xml new file mode 100644 index 000000000..a76d1297d --- /dev/null +++ b/app/src/main/res/layout/recordings.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d7ad50480..747cd551b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -289,6 +289,7 @@ No recordings. + Do you really want to delete and leave the selected recordings? Send log