Loading app/src/main/java/org/lineageos/recorder/ListActivity.java +60 −7 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package org.lineageos.recorder; import android.net.Uri; import android.os.Bundle; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; Loading @@ -34,8 +35,9 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.lineageos.recorder.list.ListActionModeCallback; import org.lineageos.recorder.list.RecordingData; import org.lineageos.recorder.list.RecordingItemCallbacks; import org.lineageos.recorder.list.RecordingListCallbacks; import org.lineageos.recorder.list.RecordingsAdapter; import org.lineageos.recorder.utils.LastRecordHelper; import org.lineageos.recorder.utils.MediaProviderHelper; Loading @@ -44,15 +46,18 @@ import org.lineageos.recorder.utils.Utils; import java.util.ArrayList; import java.util.List; public class ListActivity extends AppCompatActivity implements RecordingItemCallbacks { public class ListActivity extends AppCompatActivity implements RecordingListCallbacks { private static final String TYPE_AUDIO = "audio/*"; private RecordingsAdapter mAdapter; private Toolbar mToolbar; private RecyclerView mListView; private ProgressBar mProgressBar; private TextView mEmptyText; private ActionMode mActionMode; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Loading @@ -60,12 +65,12 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall setContentView(R.layout.activity_list); final CoordinatorLayout coordinatorLayout = findViewById(R.id.coordinator); final Toolbar toolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar); mListView = findViewById(R.id.list_view); mProgressBar = findViewById(R.id.list_loading); mEmptyText = findViewById(R.id.list_empty); setSupportActionBar(toolbar); setSupportActionBar(mToolbar); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayShowHomeEnabled(true); Loading @@ -79,6 +84,7 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall super.onItemRangeRemoved(positionStart, itemCount); if (mAdapter.getItemCount() == 0) { changeEmptyView(true); endSelectionMode(); } } Loading Loading @@ -142,14 +148,16 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall @Override public boolean onPrepareOptionsMenu(Menu menu) { MenuItem item = menu.findItem(R.id.action_delete_all); item.setEnabled(mAdapter.getItemCount() > 0); MenuItem deleteAllItem = menu.findItem(R.id.action_delete_all); boolean hasItems = mAdapter.getItemCount() > 0; deleteAllItem.setEnabled(hasItems); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_delete_all) { int id = item.getItemId(); if (id == R.id.action_delete_all) { deleteAllRecordings(); return true; } else { Loading @@ -157,6 +165,31 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall } } @Override public void startSelectionMode() { // Clear previous (should do nothing), but be sure endSelectionMode(); // Start action mode mActionMode = mToolbar.startActionMode(new ListActionModeCallback( this::deleteSelectedRecordings)); mAdapter.enterSelectionMode(); } @Override public void endSelectionMode() { if (mActionMode != null) { mActionMode.finish(); mActionMode = null; } mAdapter.exitSelectionMode(); } @Override public void onActionModeFinished(@NonNull ActionMode mode) { super.onActionModeFinished(mode); endSelectionMode(); } private void loadRecordings() { MediaProviderHelper.requestMyRecordings(getContentResolver(), list -> { mProgressBar.setVisibility(View.GONE); Loading @@ -169,6 +202,26 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall mListView.setVisibility(isEmpty ? View.GONE : View.VISIBLE); } private void deleteSelectedRecordings() { final List<RecordingData> selectedItems = mAdapter.getSelected(); if (selectedItems.isEmpty()) { return; } new AlertDialog.Builder(this) .setTitle(R.string.delete_selected_title) .setMessage(getString(R.string.delete_selected_message)) .setPositiveButton(R.string.delete, (dialog, which) -> { selectedItems.forEach(item -> { MediaProviderHelper.remove(this, item.getUri()); mAdapter.onDelete(item); }); Utils.cancelShareNotification(this); }) .setNegativeButton(R.string.cancel, null) .show(); } private void deleteAllRecordings() { final List<RecordingData> items = mAdapter.getData(); if (items.isEmpty()) { Loading app/src/main/java/org/lineageos/recorder/list/ListActionModeCallback.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The LineageOS Project * * 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. */ package org.lineageos.recorder.list; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import androidx.annotation.NonNull; import org.lineageos.recorder.R; public class ListActionModeCallback implements ActionMode.Callback { @NonNull private final Runnable mDeleteSelected; public ListActionModeCallback(@NonNull Runnable deleteSelected) { mDeleteSelected = deleteSelected; } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { final MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.menu_list_action_mode, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == R.id.action_delete_selected) { mDeleteSelected.run(); return true; } else { return false; } } @Override public void onDestroyActionMode(ActionMode mode) { } } app/src/main/java/org/lineageos/recorder/list/ListItemStatus.java 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The LineageOS Project * * 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. */ package org.lineageos.recorder.list; import androidx.annotation.IntDef; @IntDef(value = { ListItemStatus.DEFAULT, ListItemStatus.UNCHECKED, ListItemStatus.CHECKED, }) public @interface ListItemStatus { int DEFAULT = 0; int UNCHECKED = 1; int CHECKED = 2; } app/src/main/java/org/lineageos/recorder/list/RecordingItemViewHolder.java +20 −9 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ public class RecordingItemViewHolder extends RecyclerView.ViewHolder { private static final String SUMMARY_FORMAT = "%s - %02d:%02d"; private final SimpleDateFormat mDateFormat; private final ImageView mIconView; private final TextView mTitleView; private final TextView mSummaryView; @NonNull Loading @@ -52,21 +53,15 @@ public class RecordingItemViewHolder extends RecyclerView.ViewHolder { mCallbacks = callbacks; mDateFormat = dateFormat; mIconView = itemView.findViewById(R.id.item_play); mTitleView = itemView.findViewById(R.id.item_title); mSummaryView = itemView.findViewById(R.id.item_date); final ImageView playView = itemView.findViewById(R.id.item_play); final ImageView menuView = itemView.findViewById(R.id.item_menu); playView.setOnClickListener(v -> mCallbacks.onPlay(mUri)); menuView.setOnClickListener(this::showPopupMenu); itemView.setOnClickListener(v -> mCallbacks.onPlay(mUri)); itemView.setOnLongClickListener(v -> { showPopupMenu(menuView); return true; }); } public void setData(@NonNull RecordingData data) { public void setData(@NonNull RecordingData data, @ListItemStatus int selection) { mUri = data.getUri(); mTitleView.setText(data.getTitle()); long seconds = data.getDuration() / 1000; Loading @@ -74,6 +69,22 @@ public class RecordingItemViewHolder extends RecyclerView.ViewHolder { seconds -= (minutes * 60); mSummaryView.setText(String.format(Locale.getDefault(), SUMMARY_FORMAT, mDateFormat.format(data.getDate()), minutes, seconds)); switch (selection) { case ListItemStatus.DEFAULT: mIconView.setImageResource(R.drawable.ic_play_circle_outline); break; case ListItemStatus.UNCHECKED: mIconView.setImageResource(R.drawable.ic_list_unchecked); break; case ListItemStatus.CHECKED: mIconView.setImageResource(R.drawable.ic_list_checked); break; } } public Uri getUri() { return mUri; } @SuppressLint("RestrictedApi") Loading app/src/main/java/org/lineageos/recorder/list/RecordingListCallbacks.java 0 → 100644 +21 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The LineageOS Project * * 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. */ package org.lineageos.recorder.list; public interface RecordingListCallbacks extends RecordingItemCallbacks { void startSelectionMode(); void endSelectionMode(); } Loading
app/src/main/java/org/lineageos/recorder/ListActivity.java +60 −7 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package org.lineageos.recorder; import android.net.Uri; import android.os.Bundle; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; Loading @@ -34,8 +35,9 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.lineageos.recorder.list.ListActionModeCallback; import org.lineageos.recorder.list.RecordingData; import org.lineageos.recorder.list.RecordingItemCallbacks; import org.lineageos.recorder.list.RecordingListCallbacks; import org.lineageos.recorder.list.RecordingsAdapter; import org.lineageos.recorder.utils.LastRecordHelper; import org.lineageos.recorder.utils.MediaProviderHelper; Loading @@ -44,15 +46,18 @@ import org.lineageos.recorder.utils.Utils; import java.util.ArrayList; import java.util.List; public class ListActivity extends AppCompatActivity implements RecordingItemCallbacks { public class ListActivity extends AppCompatActivity implements RecordingListCallbacks { private static final String TYPE_AUDIO = "audio/*"; private RecordingsAdapter mAdapter; private Toolbar mToolbar; private RecyclerView mListView; private ProgressBar mProgressBar; private TextView mEmptyText; private ActionMode mActionMode; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Loading @@ -60,12 +65,12 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall setContentView(R.layout.activity_list); final CoordinatorLayout coordinatorLayout = findViewById(R.id.coordinator); final Toolbar toolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar); mListView = findViewById(R.id.list_view); mProgressBar = findViewById(R.id.list_loading); mEmptyText = findViewById(R.id.list_empty); setSupportActionBar(toolbar); setSupportActionBar(mToolbar); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayShowHomeEnabled(true); Loading @@ -79,6 +84,7 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall super.onItemRangeRemoved(positionStart, itemCount); if (mAdapter.getItemCount() == 0) { changeEmptyView(true); endSelectionMode(); } } Loading Loading @@ -142,14 +148,16 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall @Override public boolean onPrepareOptionsMenu(Menu menu) { MenuItem item = menu.findItem(R.id.action_delete_all); item.setEnabled(mAdapter.getItemCount() > 0); MenuItem deleteAllItem = menu.findItem(R.id.action_delete_all); boolean hasItems = mAdapter.getItemCount() > 0; deleteAllItem.setEnabled(hasItems); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_delete_all) { int id = item.getItemId(); if (id == R.id.action_delete_all) { deleteAllRecordings(); return true; } else { Loading @@ -157,6 +165,31 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall } } @Override public void startSelectionMode() { // Clear previous (should do nothing), but be sure endSelectionMode(); // Start action mode mActionMode = mToolbar.startActionMode(new ListActionModeCallback( this::deleteSelectedRecordings)); mAdapter.enterSelectionMode(); } @Override public void endSelectionMode() { if (mActionMode != null) { mActionMode.finish(); mActionMode = null; } mAdapter.exitSelectionMode(); } @Override public void onActionModeFinished(@NonNull ActionMode mode) { super.onActionModeFinished(mode); endSelectionMode(); } private void loadRecordings() { MediaProviderHelper.requestMyRecordings(getContentResolver(), list -> { mProgressBar.setVisibility(View.GONE); Loading @@ -169,6 +202,26 @@ public class ListActivity extends AppCompatActivity implements RecordingItemCall mListView.setVisibility(isEmpty ? View.GONE : View.VISIBLE); } private void deleteSelectedRecordings() { final List<RecordingData> selectedItems = mAdapter.getSelected(); if (selectedItems.isEmpty()) { return; } new AlertDialog.Builder(this) .setTitle(R.string.delete_selected_title) .setMessage(getString(R.string.delete_selected_message)) .setPositiveButton(R.string.delete, (dialog, which) -> { selectedItems.forEach(item -> { MediaProviderHelper.remove(this, item.getUri()); mAdapter.onDelete(item); }); Utils.cancelShareNotification(this); }) .setNegativeButton(R.string.cancel, null) .show(); } private void deleteAllRecordings() { final List<RecordingData> items = mAdapter.getData(); if (items.isEmpty()) { Loading
app/src/main/java/org/lineageos/recorder/list/ListActionModeCallback.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The LineageOS Project * * 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. */ package org.lineageos.recorder.list; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import androidx.annotation.NonNull; import org.lineageos.recorder.R; public class ListActionModeCallback implements ActionMode.Callback { @NonNull private final Runnable mDeleteSelected; public ListActionModeCallback(@NonNull Runnable deleteSelected) { mDeleteSelected = deleteSelected; } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { final MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.menu_list_action_mode, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { if (item.getItemId() == R.id.action_delete_selected) { mDeleteSelected.run(); return true; } else { return false; } } @Override public void onDestroyActionMode(ActionMode mode) { } }
app/src/main/java/org/lineageos/recorder/list/ListItemStatus.java 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The LineageOS Project * * 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. */ package org.lineageos.recorder.list; import androidx.annotation.IntDef; @IntDef(value = { ListItemStatus.DEFAULT, ListItemStatus.UNCHECKED, ListItemStatus.CHECKED, }) public @interface ListItemStatus { int DEFAULT = 0; int UNCHECKED = 1; int CHECKED = 2; }
app/src/main/java/org/lineageos/recorder/list/RecordingItemViewHolder.java +20 −9 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ public class RecordingItemViewHolder extends RecyclerView.ViewHolder { private static final String SUMMARY_FORMAT = "%s - %02d:%02d"; private final SimpleDateFormat mDateFormat; private final ImageView mIconView; private final TextView mTitleView; private final TextView mSummaryView; @NonNull Loading @@ -52,21 +53,15 @@ public class RecordingItemViewHolder extends RecyclerView.ViewHolder { mCallbacks = callbacks; mDateFormat = dateFormat; mIconView = itemView.findViewById(R.id.item_play); mTitleView = itemView.findViewById(R.id.item_title); mSummaryView = itemView.findViewById(R.id.item_date); final ImageView playView = itemView.findViewById(R.id.item_play); final ImageView menuView = itemView.findViewById(R.id.item_menu); playView.setOnClickListener(v -> mCallbacks.onPlay(mUri)); menuView.setOnClickListener(this::showPopupMenu); itemView.setOnClickListener(v -> mCallbacks.onPlay(mUri)); itemView.setOnLongClickListener(v -> { showPopupMenu(menuView); return true; }); } public void setData(@NonNull RecordingData data) { public void setData(@NonNull RecordingData data, @ListItemStatus int selection) { mUri = data.getUri(); mTitleView.setText(data.getTitle()); long seconds = data.getDuration() / 1000; Loading @@ -74,6 +69,22 @@ public class RecordingItemViewHolder extends RecyclerView.ViewHolder { seconds -= (minutes * 60); mSummaryView.setText(String.format(Locale.getDefault(), SUMMARY_FORMAT, mDateFormat.format(data.getDate()), minutes, seconds)); switch (selection) { case ListItemStatus.DEFAULT: mIconView.setImageResource(R.drawable.ic_play_circle_outline); break; case ListItemStatus.UNCHECKED: mIconView.setImageResource(R.drawable.ic_list_unchecked); break; case ListItemStatus.CHECKED: mIconView.setImageResource(R.drawable.ic_list_checked); break; } } public Uri getUri() { return mUri; } @SuppressLint("RestrictedApi") Loading
app/src/main/java/org/lineageos/recorder/list/RecordingListCallbacks.java 0 → 100644 +21 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The LineageOS Project * * 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. */ package org.lineageos.recorder.list; public interface RecordingListCallbacks extends RecordingItemCallbacks { void startSelectionMode(); void endSelectionMode(); }