From 15b4a7d0554d6b904629e12b233048d4bb5fc409 Mon Sep 17 00:00:00 2001 From: Somethingweirdhere <36226087+Somethingweirdhere@users.noreply.github.com> Date: Tue, 17 Apr 2018 19:19:12 +0200 Subject: [PATCH 1/2] Fixed crash when trying to open a downloaded file without a player --- MissionAdapter.java | 381 +++++++++++++++++++++++++++++++++++ strings.xml | 471 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 852 insertions(+) create mode 100644 MissionAdapter.java create mode 100644 strings.xml diff --git a/MissionAdapter.java b/MissionAdapter.java new file mode 100644 index 000000000..af25eaecb --- /dev/null +++ b/MissionAdapter.java @@ -0,0 +1,381 @@ +package us.shandian.giga.ui.adapter; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.support.v4.content.FileProvider; +import android.support.v4.view.ViewCompat; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.MimeTypeMap; +import android.widget.ImageView; +import android.widget.PopupMenu; +import android.widget.TextView; +import android.widget.Toast; + +import org.schabi.newpipe.R; + +import java.io.File; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.get.DownloadMission; +import us.shandian.giga.service.DownloadManagerService; +import us.shandian.giga.ui.common.ProgressDrawable; +import us.shandian.giga.util.Utility; + +import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; +import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; + +public class MissionAdapter extends RecyclerView.Adapter { + private static final Map ALGORITHMS = new HashMap<>(); + private static final String TAG = "MissionAdapter"; + + static { + ALGORITHMS.put(R.id.md5, "MD5"); + ALGORITHMS.put(R.id.sha1, "SHA1"); + } + + private Context mContext; + private LayoutInflater mInflater; + private DownloadManager mManager; + private DownloadManagerService.DMBinder mBinder; + private int mLayout; + + public MissionAdapter(Context context, DownloadManagerService.DMBinder binder, DownloadManager manager, boolean isLinear) { + mContext = context; + mManager = manager; + mBinder = binder; + + mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + mLayout = isLinear ? R.layout.mission_item_linear : R.layout.mission_item; + } + + @Override + public MissionAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + final ViewHolder h = new ViewHolder(mInflater.inflate(mLayout, parent, false)); + + h.menu.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + buildPopup(h); + } + }); + + /*h.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showDetail(h); + } + });*/ + + return h; + } + + @Override + public void onViewRecycled(MissionAdapter.ViewHolder h) { + super.onViewRecycled(h); + h.mission.removeListener(h.observer); + h.mission = null; + h.observer = null; + h.progress = null; + h.position = -1; + h.lastTimeStamp = -1; + h.lastDone = -1; + h.colorId = 0; + } + + @Override + public void onBindViewHolder(MissionAdapter.ViewHolder h, int pos) { + DownloadMission ms = mManager.getMission(pos); + h.mission = ms; + h.position = pos; + + Utility.FileType type = Utility.getFileType(ms.name); + + h.icon.setImageResource(Utility.getIconForFileType(type)); + h.name.setText(ms.name); + h.size.setText(Utility.formatBytes(ms.length)); + + h.progress = new ProgressDrawable(mContext, Utility.getBackgroundForFileType(type), Utility.getForegroundForFileType(type)); + ViewCompat.setBackground(h.bkg, h.progress); + + h.observer = new MissionObserver(this, h); + ms.addListener(h.observer); + + updateProgress(h); + } + + @Override + public int getItemCount() { + return mManager.getCount(); + } + + @Override + public long getItemId(int position) { + return position; + } + + private void updateProgress(ViewHolder h) { + updateProgress(h, false); + } + + private void updateProgress(ViewHolder h, boolean finished) { + if (h.mission == null) return; + + long now = System.currentTimeMillis(); + + if (h.lastTimeStamp == -1) { + h.lastTimeStamp = now; + } + + if (h.lastDone == -1) { + h.lastDone = h.mission.done; + } + + long deltaTime = now - h.lastTimeStamp; + long deltaDone = h.mission.done - h.lastDone; + + if (deltaTime == 0 || deltaTime > 1000 || finished) { + if (h.mission.errCode > 0) { + h.status.setText(R.string.msg_error); + } else { + float progress = (float) h.mission.done / h.mission.length; + h.status.setText(String.format(Locale.US, "%.2f%%", progress * 100)); + h.progress.setProgress(progress); + } + } + + if (deltaTime > 1000 && deltaDone > 0) { + float speed = (float) deltaDone / deltaTime; + String speedStr = Utility.formatSpeed(speed * 1000); + String sizeStr = Utility.formatBytes(h.mission.length); + + h.size.setText(sizeStr + " " + speedStr); + + h.lastTimeStamp = now; + h.lastDone = h.mission.done; + } + } + + + private void buildPopup(final ViewHolder h) { + PopupMenu popup = new PopupMenu(mContext, h.menu); + popup.inflate(R.menu.mission); + + Menu menu = popup.getMenu(); + MenuItem start = menu.findItem(R.id.start); + MenuItem pause = menu.findItem(R.id.pause); + MenuItem view = menu.findItem(R.id.view); + MenuItem delete = menu.findItem(R.id.delete); + MenuItem checksum = menu.findItem(R.id.checksum); + + // Set to false first + start.setVisible(false); + pause.setVisible(false); + view.setVisible(false); + delete.setVisible(false); + checksum.setVisible(false); + + if (!h.mission.finished) { + if (!h.mission.running) { + if (h.mission.errCode == -1) { + start.setVisible(true); + } + + delete.setVisible(true); + } else { + pause.setVisible(true); + } + } else { + view.setVisible(true); + delete.setVisible(true); + checksum.setVisible(true); + } + + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + int id = item.getItemId(); + switch (id) { + case R.id.start: + mManager.resumeMission(h.position); + mBinder.onMissionAdded(mManager.getMission(h.position)); + return true; + case R.id.pause: + mManager.pauseMission(h.position); + mBinder.onMissionRemoved(mManager.getMission(h.position)); + h.lastTimeStamp = -1; + h.lastDone = -1; + return true; + case R.id.view: + File f = new File(h.mission.location, h.mission.name); + String ext = Utility.getFileExt(h.mission.name); + + Log.d(TAG, "Viewing file: " + f.getAbsolutePath() + " ext: " + ext); + + if (ext == null) { + Log.w(TAG, "Can't view file because it has no extension: " + + h.mission.name); + return false; + } + + String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1)); + Log.v(TAG, "Mime: " + mime + " package: " + mContext.getApplicationContext().getPackageName() + ".provider"); + if (f.exists()) { + viewFileWithFileProvider(f, mime); + } else { + Log.w(TAG, "File doesn't exist"); + } + + return true; + case R.id.delete: + mManager.deleteMission(h.position); + notifyDataSetChanged(); + return true; + case R.id.md5: + case R.id.sha1: + DownloadMission mission = mManager.getMission(h.position); + new ChecksumTask().execute(mission.location + "/" + mission.name, ALGORITHMS.get(id)); + return true; + default: + return false; + } + } + }); + + popup.show(); + } + + private void viewFile(File file, String mimetype) { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.fromFile(file), mimetype); + intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION); + } + //mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + Log.v(TAG, "Starting intent: " + intent); + mContext.startActivity(intent); + } + + private void viewFileWithFileProvider(File file, String mimetype) { + String ourPackage = mContext.getApplicationContext().getPackageName(); + Uri uri = FileProvider.getUriForFile(mContext, ourPackage + ".provider", file); + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.setDataAndType(uri, mimetype); + intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION); + } + //mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + Log.v(TAG, "Starting intent: " + intent); + if (intent.resolveActivity(mContext.getPackageManager()) != null) { + mContext.startActivity(intent); + } else { + Toast noPlayerToast = Toast.makeText(mContext, R.string.toast_no_player, Toast.LENGTH_LONG); + noPlayerToast.show(); + } + } + + static class ViewHolder extends RecyclerView.ViewHolder { + public DownloadMission mission; + public int position; + + public TextView status; + public ImageView icon; + public TextView name; + public TextView size; + public View bkg; + public ImageView menu; + public ProgressDrawable progress; + public MissionObserver observer; + + public long lastTimeStamp = -1; + public long lastDone = -1; + public int colorId; + + public ViewHolder(View v) { + super(v); + + status = v.findViewById(R.id.item_status); + icon = v.findViewById(R.id.item_icon); + name = v.findViewById(R.id.item_name); + size = v.findViewById(R.id.item_size); + bkg = v.findViewById(R.id.item_bkg); + menu = v.findViewById(R.id.item_more); + } + } + + static class MissionObserver implements DownloadMission.MissionListener { + private MissionAdapter mAdapter; + private ViewHolder mHolder; + + public MissionObserver(MissionAdapter adapter, ViewHolder holder) { + mAdapter = adapter; + mHolder = holder; + } + + @Override + public void onProgressUpdate(DownloadMission downloadMission, long done, long total) { + mAdapter.updateProgress(mHolder); + } + + @Override + public void onFinish(DownloadMission downloadMission) { + //mAdapter.mManager.deleteMission(mHolder.position); + // TODO Notification + //mAdapter.notifyDataSetChanged(); + if (mHolder.mission != null) { + mHolder.size.setText(Utility.formatBytes(mHolder.mission.length)); + mAdapter.updateProgress(mHolder, true); + } + } + + @Override + public void onError(DownloadMission downloadMission, int errCode) { + mAdapter.updateProgress(mHolder); + } + + } + + private class ChecksumTask extends AsyncTask { + ProgressDialog prog; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + // Create dialog + prog = new ProgressDialog(mContext); + prog.setCancelable(false); + prog.setMessage(mContext.getString(R.string.msg_wait)); + prog.show(); + } + + @Override + protected String doInBackground(String... params) { + return Utility.checksum(params[0], params[1]); + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + prog.dismiss(); + Utility.copyToClipboard(mContext, result); + } + } +} diff --git a/strings.xml b/strings.xml new file mode 100644 index 000000000..939e0df13 --- /dev/null +++ b/strings.xml @@ -0,0 +1,471 @@ + + + NewPipe + Tap search to get started + %1$s views + Published on %1$s + No stream player found. Do you want to install VLC? + No stream player found (you can install VLC to play it) + Install + Cancel + https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc + Open in browser + Open in popup mode + Share + Download + Download stream file. + Search + Settings + Did you mean: %1$s ? + Share with + Choose browser + rotation + Use external video player + Some resolutions will NOT have audio when this option is enabled + Use external audio player + NewPipe popup mode + RSS + Subscribe + Subscribed + Channel unsubscribed + Unable to change subscription + Unable to update subscription + Show info + + Main + Subscriptions + Bookmarks + + What\'s New + + Background + Popup + Add To + + Video download path + Path to store downloaded videos in + Enter download path for videos + + Audio download path + Path to store downloaded audio in + Enter download path for audio files + + Autoplay + Automatically plays a video when NewPipe is called from another app + Default resolution + Default popup resolution + Show higher resolutions + Only some devices support playing 2K/4K videos + Play with Kodi + Kore app not found. Install it? + org.xbmc.kore + Show \"Play with Kodi\" option + Display an option to play a video via Kodi media center + Audio + Default audio format + Default video format + WebM — free format + M4A — better quality + Theme + Light + Dark + Black + Remember popup size and position + Remember last size and position of popup + Use fast inexact seek + Inexact seek allows the player to seek to positions faster with reduced precision + Load thumbnails + Disable to stop all thumbnails from loading and save on data and memory usage. Changing this will clear both in-memory and on-disk image cache. + Image cache wiped + Wipe cached metadata + Remove all cached webpage data + Metadata cache wiped + Auto-queue next stream + Automatically append a related stream when playback starts on the last stream in a non-repeating play queue. + Player gesture controls + Use gestures to control the brightness and volume of the player + Search suggestions + Show suggestions when searching + Search history + Store search queries locally + History + Keep track of watched videos + Resume on focus gain + Continue playing after interruptions (e.g. phone calls) + Download + Next video + Show next and similar videos + Show hold to append tip + Show tip when background or popup button is pressed on video details page + URL not supported + Default content country + Service + Default content language + Player + Behavior + Video & Audio + History & Cache + Popup + Appearance + Other + Debug + Playing in background + Playing in popup mode + Queued on background player + Queued on popup player + https://www.c3s.cc/ + Play + Content + Show age restricted content + Age Restricted Video. Allowing such material is possible from Settings. + live + LIVE + Downloads + Downloads + Error report + All + Channel + Playlist + Yes + Later + Disabled + Filter + Refresh + Clear + Resizing + Best resolution + Undo + Play All + Always + Just Once + File + + newpipe + NewPipe Notification + Notifications for NewPipe Background and Popup Players + + [Unknown] + + Toggle Orientation + Switch to Background + Switch to Popup + Switch to Main + + Import database + Export database + Will override your current history and subscriptions + Export history, subscriptions and playlists. + + Error + Network error + Could not load all thumbnails + Could not decrypt video URL signature + Could not parse website + Could not parse website completely + Content not available + Blocked by GEMA + Could not set up download menu + This is a LIVE STREAM, which is not yet supported. + Could not get any stream + Could not load image + App/UI crashed + Failed to play this stream + Unrecoverable player error occurred + Recovering from player error + External players don\'t support these types of links + Invalid URL + No video streams found + No audio streams found + Invalid directory + Invalid file/content source + File doesn\'t exist or insufficient permission to read or write to it + File name cannot be empty + An error occurred: %1$s + No streams available to download + + + Sorry, that should not have happened. + Guru Meditation. + Report error via e-mail + Sorry, some errors occurred. + REPORT + Info: + What happened: + What:\\nRequest:\\nContent Lang:\\nService:\\nGMT Time:\\nPackage:\\nVersion:\\nOS version: + Your comment (in English): + Details: + + + + Video preview thumbnail + Video preview thumbnail + Uploader\'s avatar thumbnail + Likes + Dislikes + Use Tor + (Experimental) Force download traffic through Tor for increased privacy (streaming videos not yet supported). + Report an Error + User report + No results + @string/no_videos + Nothing Here But Crickets + Drag to reorder + + Cannot create download directory \'%1$s\' + Created download directory \'%1$s\' + + Video + Audio + Retry + Storage access permission denied + Use old player + Old built-in Mediaframework player + + K + M + B + + + No subscribers + + %s subscriber + %s subscribers + + + No views + + %s view + %s views + + + No videos + + %s video + %s videos + + + + Start + Pause + Play + Create + Delete + Delete One + Delete All + Checksum + Dismiss + Rename + + + New mission + OK + + + Filename + Threads + Error + Server unsupported + File already exists + Malformed URL or Internet not available + NewPipe Downloading + Tap for details + Please wait… + Copied to clipboard + Please select an available download folder + This permission is needed to\nopen in popup mode + + + MD5 + SHA-1 + reCAPTCHA + reCAPTCHA Challenge + reCAPTCHA Challenge requested + + + + + Download + Allowed characters in filenames + Invalid characters are replaced with this value + Replacement character + + [^\\w\\d]+ + [\\n\\r|\\?*<":>/']+ + Letters and digits + Most special characters + + No player has been found for this file + + + About NewPipe + Settings + About + Third-party Licenses + © %1$s by %2$s under %3$s + Could not load license + Open website + About + Contributors + Licenses + A free lightweight YouTube frontend for Android. + Contribute + Whether you have ideas of; translation, design changes, code cleaning, or real heavy code changes—help is always welcome. The more is done the better it gets! + https://github.com/TeamNewPipe/NewPipe + View on GitHub + Donate + NewPipe gets developed by volunteers which spend their free time to bring the best experience to you. Now it is time to give back to make sure our developers can make NewPipe even more better while enjoying a cup of java! + https://newpipe.schabi.org/donate + Give back + Website + To get more information and the latest news about NewPipe visit our website. + https://newpipe.schabi.org/ + NewPipe\'s License + NewPipe is Free Software: You can use, study share and improve it at your will. Specifically you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + Read license + + + + History + Searched + Watched + History is disabled + History + The history is empty + History cleared + Item deleted + Do you want to delete this item from search history? + Do you want to delete this item from watch history? + Are you sure you want to delete all items from history? + Last Played + Most Played + + + Content of main page + Blank Page + Kiosk Page + Subscription Page + Feed Page + Channel Page + + @string/blank_page_summary + @string/kiosk_page_summary + @string/feed_page_summary + @string/subscription_page_summary + @string/channel_page_summary + + Select a channel + No channel subscribed yet + Select a kiosk + Export complete + Import complete + No valid ZIP file + Warning: Could not import all files. + This will override your current setup. + + + Kiosk + Trending + Top 50 + New & hot + %1$s/%2$s + + + Background Player + Popup Player + Remove + Details + Audio Settings + Hold To Enqueue + Enqueue on Background + Enqueue on Popup + Start Playing Here + Start Here on Background + Start Here on Popup + + + Open Drawer + Close Drawer + YouTube + SoundCloud + Something will come here soon ;D + + + + NewPipe + Preferred open action + Default action when opening content — %s + + Video player + Background player + Popup player + Always ask + + Getting info… + "The requested content is loading" + + + Create New Playlist + Delete Playlist + Rename Playlist + Name + Add To Playlist + Set as Playlist Thumbnail + + Bookmark Playlist + Remove Bookmark + + Do you want to delete this playlist? + Playlist successfully created + Added to playlist + Playlist thumbnail changed + Failed to delete playlist + + + No Caption + + FIT + FILL + ZOOM + + Auto-generated + + + Caption + Modify player caption text scale and background styles. Require player restart to take effect. + + + Enable LeakCanary + Memory leak monitoring may cause app to become unresponsive when heap dumping + + Report Out-of-lifecycle errors + Force reporting of undeliverable Rx exceptions occurring outside of fragment or activity lifecycle after dispose + + + Import/Export + Import + Import from + Export to + + Importing… + Exporting… + + Import file + Previous export + + Subscriptions import failed + Subscriptions export failed + + To import your YouTube subscriptions you will need the export file, which can be downloaded following these instructions:\n\n1. Go to this url: %1$s\n2. Log in to your account when asked\n3. A download should start (that\'s the export file) + To import your SoundCloud followings you have to know your profile url or id. If you do, just type either of them in the input below and you\'re ready to go.\n\nIf you don\'t, you can follow these steps:\n\n1. Enable \"desktop mode\" in some browser (the site is not available for mobile devices)\n2. Go to this url: %1$s\n3. Log in to your account when asked\n4. Copy the url that you were redirected to (that\'s your profile url) + yourid, soundcloud.com/yourid + + Keep in mind that this operation can be network expensive.\n\nDo you want to continue? + + + Playback Speed Control + Tempo + Pitch + Unhook (may cause distortion) + Nightcore + Default + From 85dc5553585023d5be7ac99390dd7b6679ee8376 Mon Sep 17 00:00:00 2001 From: Somethingweirdhere Date: Tue, 17 Apr 2018 19:47:17 +0200 Subject: [PATCH 2/2] Fixed crash when trying to open a downloaded file without a player --- MissionAdapter.java | 381 -------------- .../giga/ui/adapter/MissionAdapter.java | 8 +- app/src/main/res/values/strings.xml | 2 + strings.xml | 471 ------------------ 4 files changed, 9 insertions(+), 853 deletions(-) delete mode 100644 MissionAdapter.java delete mode 100644 strings.xml diff --git a/MissionAdapter.java b/MissionAdapter.java deleted file mode 100644 index af25eaecb..000000000 --- a/MissionAdapter.java +++ /dev/null @@ -1,381 +0,0 @@ -package us.shandian.giga.ui.adapter; - -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Build; -import android.support.v4.content.FileProvider; -import android.support.v4.view.ViewCompat; -import android.support.v7.widget.RecyclerView; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.MimeTypeMap; -import android.widget.ImageView; -import android.widget.PopupMenu; -import android.widget.TextView; -import android.widget.Toast; - -import org.schabi.newpipe.R; - -import java.io.File; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import us.shandian.giga.get.DownloadManager; -import us.shandian.giga.get.DownloadMission; -import us.shandian.giga.service.DownloadManagerService; -import us.shandian.giga.ui.common.ProgressDrawable; -import us.shandian.giga.util.Utility; - -import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; -import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; - -public class MissionAdapter extends RecyclerView.Adapter { - private static final Map ALGORITHMS = new HashMap<>(); - private static final String TAG = "MissionAdapter"; - - static { - ALGORITHMS.put(R.id.md5, "MD5"); - ALGORITHMS.put(R.id.sha1, "SHA1"); - } - - private Context mContext; - private LayoutInflater mInflater; - private DownloadManager mManager; - private DownloadManagerService.DMBinder mBinder; - private int mLayout; - - public MissionAdapter(Context context, DownloadManagerService.DMBinder binder, DownloadManager manager, boolean isLinear) { - mContext = context; - mManager = manager; - mBinder = binder; - - mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - mLayout = isLinear ? R.layout.mission_item_linear : R.layout.mission_item; - } - - @Override - public MissionAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - final ViewHolder h = new ViewHolder(mInflater.inflate(mLayout, parent, false)); - - h.menu.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - buildPopup(h); - } - }); - - /*h.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showDetail(h); - } - });*/ - - return h; - } - - @Override - public void onViewRecycled(MissionAdapter.ViewHolder h) { - super.onViewRecycled(h); - h.mission.removeListener(h.observer); - h.mission = null; - h.observer = null; - h.progress = null; - h.position = -1; - h.lastTimeStamp = -1; - h.lastDone = -1; - h.colorId = 0; - } - - @Override - public void onBindViewHolder(MissionAdapter.ViewHolder h, int pos) { - DownloadMission ms = mManager.getMission(pos); - h.mission = ms; - h.position = pos; - - Utility.FileType type = Utility.getFileType(ms.name); - - h.icon.setImageResource(Utility.getIconForFileType(type)); - h.name.setText(ms.name); - h.size.setText(Utility.formatBytes(ms.length)); - - h.progress = new ProgressDrawable(mContext, Utility.getBackgroundForFileType(type), Utility.getForegroundForFileType(type)); - ViewCompat.setBackground(h.bkg, h.progress); - - h.observer = new MissionObserver(this, h); - ms.addListener(h.observer); - - updateProgress(h); - } - - @Override - public int getItemCount() { - return mManager.getCount(); - } - - @Override - public long getItemId(int position) { - return position; - } - - private void updateProgress(ViewHolder h) { - updateProgress(h, false); - } - - private void updateProgress(ViewHolder h, boolean finished) { - if (h.mission == null) return; - - long now = System.currentTimeMillis(); - - if (h.lastTimeStamp == -1) { - h.lastTimeStamp = now; - } - - if (h.lastDone == -1) { - h.lastDone = h.mission.done; - } - - long deltaTime = now - h.lastTimeStamp; - long deltaDone = h.mission.done - h.lastDone; - - if (deltaTime == 0 || deltaTime > 1000 || finished) { - if (h.mission.errCode > 0) { - h.status.setText(R.string.msg_error); - } else { - float progress = (float) h.mission.done / h.mission.length; - h.status.setText(String.format(Locale.US, "%.2f%%", progress * 100)); - h.progress.setProgress(progress); - } - } - - if (deltaTime > 1000 && deltaDone > 0) { - float speed = (float) deltaDone / deltaTime; - String speedStr = Utility.formatSpeed(speed * 1000); - String sizeStr = Utility.formatBytes(h.mission.length); - - h.size.setText(sizeStr + " " + speedStr); - - h.lastTimeStamp = now; - h.lastDone = h.mission.done; - } - } - - - private void buildPopup(final ViewHolder h) { - PopupMenu popup = new PopupMenu(mContext, h.menu); - popup.inflate(R.menu.mission); - - Menu menu = popup.getMenu(); - MenuItem start = menu.findItem(R.id.start); - MenuItem pause = menu.findItem(R.id.pause); - MenuItem view = menu.findItem(R.id.view); - MenuItem delete = menu.findItem(R.id.delete); - MenuItem checksum = menu.findItem(R.id.checksum); - - // Set to false first - start.setVisible(false); - pause.setVisible(false); - view.setVisible(false); - delete.setVisible(false); - checksum.setVisible(false); - - if (!h.mission.finished) { - if (!h.mission.running) { - if (h.mission.errCode == -1) { - start.setVisible(true); - } - - delete.setVisible(true); - } else { - pause.setVisible(true); - } - } else { - view.setVisible(true); - delete.setVisible(true); - checksum.setVisible(true); - } - - popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - int id = item.getItemId(); - switch (id) { - case R.id.start: - mManager.resumeMission(h.position); - mBinder.onMissionAdded(mManager.getMission(h.position)); - return true; - case R.id.pause: - mManager.pauseMission(h.position); - mBinder.onMissionRemoved(mManager.getMission(h.position)); - h.lastTimeStamp = -1; - h.lastDone = -1; - return true; - case R.id.view: - File f = new File(h.mission.location, h.mission.name); - String ext = Utility.getFileExt(h.mission.name); - - Log.d(TAG, "Viewing file: " + f.getAbsolutePath() + " ext: " + ext); - - if (ext == null) { - Log.w(TAG, "Can't view file because it has no extension: " + - h.mission.name); - return false; - } - - String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1)); - Log.v(TAG, "Mime: " + mime + " package: " + mContext.getApplicationContext().getPackageName() + ".provider"); - if (f.exists()) { - viewFileWithFileProvider(f, mime); - } else { - Log.w(TAG, "File doesn't exist"); - } - - return true; - case R.id.delete: - mManager.deleteMission(h.position); - notifyDataSetChanged(); - return true; - case R.id.md5: - case R.id.sha1: - DownloadMission mission = mManager.getMission(h.position); - new ChecksumTask().execute(mission.location + "/" + mission.name, ALGORITHMS.get(id)); - return true; - default: - return false; - } - } - }); - - popup.show(); - } - - private void viewFile(File file, String mimetype) { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), mimetype); - intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION); - } - //mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); - Log.v(TAG, "Starting intent: " + intent); - mContext.startActivity(intent); - } - - private void viewFileWithFileProvider(File file, String mimetype) { - String ourPackage = mContext.getApplicationContext().getPackageName(); - Uri uri = FileProvider.getUriForFile(mContext, ourPackage + ".provider", file); - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.setDataAndType(uri, mimetype); - intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION); - } - //mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); - Log.v(TAG, "Starting intent: " + intent); - if (intent.resolveActivity(mContext.getPackageManager()) != null) { - mContext.startActivity(intent); - } else { - Toast noPlayerToast = Toast.makeText(mContext, R.string.toast_no_player, Toast.LENGTH_LONG); - noPlayerToast.show(); - } - } - - static class ViewHolder extends RecyclerView.ViewHolder { - public DownloadMission mission; - public int position; - - public TextView status; - public ImageView icon; - public TextView name; - public TextView size; - public View bkg; - public ImageView menu; - public ProgressDrawable progress; - public MissionObserver observer; - - public long lastTimeStamp = -1; - public long lastDone = -1; - public int colorId; - - public ViewHolder(View v) { - super(v); - - status = v.findViewById(R.id.item_status); - icon = v.findViewById(R.id.item_icon); - name = v.findViewById(R.id.item_name); - size = v.findViewById(R.id.item_size); - bkg = v.findViewById(R.id.item_bkg); - menu = v.findViewById(R.id.item_more); - } - } - - static class MissionObserver implements DownloadMission.MissionListener { - private MissionAdapter mAdapter; - private ViewHolder mHolder; - - public MissionObserver(MissionAdapter adapter, ViewHolder holder) { - mAdapter = adapter; - mHolder = holder; - } - - @Override - public void onProgressUpdate(DownloadMission downloadMission, long done, long total) { - mAdapter.updateProgress(mHolder); - } - - @Override - public void onFinish(DownloadMission downloadMission) { - //mAdapter.mManager.deleteMission(mHolder.position); - // TODO Notification - //mAdapter.notifyDataSetChanged(); - if (mHolder.mission != null) { - mHolder.size.setText(Utility.formatBytes(mHolder.mission.length)); - mAdapter.updateProgress(mHolder, true); - } - } - - @Override - public void onError(DownloadMission downloadMission, int errCode) { - mAdapter.updateProgress(mHolder); - } - - } - - private class ChecksumTask extends AsyncTask { - ProgressDialog prog; - - @Override - protected void onPreExecute() { - super.onPreExecute(); - - // Create dialog - prog = new ProgressDialog(mContext); - prog.setCancelable(false); - prog.setMessage(mContext.getString(R.string.msg_wait)); - prog.show(); - } - - @Override - protected String doInBackground(String... params) { - return Utility.checksum(params[0], params[1]); - } - - @Override - protected void onPostExecute(String result) { - super.onPostExecute(result); - prog.dismiss(); - Utility.copyToClipboard(mContext, result); - } - } -} diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index de92bbdf8..af25eaecb 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -19,6 +19,7 @@ import android.webkit.MimeTypeMap; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; +import android.widget.Toast; import org.schabi.newpipe.R; @@ -282,7 +283,12 @@ public class MissionAdapter extends RecyclerView.AdapterLetters and digits Most special characters + No player has been found for this file + About NewPipe Settings diff --git a/strings.xml b/strings.xml deleted file mode 100644 index 939e0df13..000000000 --- a/strings.xml +++ /dev/null @@ -1,471 +0,0 @@ - - - NewPipe - Tap search to get started - %1$s views - Published on %1$s - No stream player found. Do you want to install VLC? - No stream player found (you can install VLC to play it) - Install - Cancel - https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc - Open in browser - Open in popup mode - Share - Download - Download stream file. - Search - Settings - Did you mean: %1$s ? - Share with - Choose browser - rotation - Use external video player - Some resolutions will NOT have audio when this option is enabled - Use external audio player - NewPipe popup mode - RSS - Subscribe - Subscribed - Channel unsubscribed - Unable to change subscription - Unable to update subscription - Show info - - Main - Subscriptions - Bookmarks - - What\'s New - - Background - Popup - Add To - - Video download path - Path to store downloaded videos in - Enter download path for videos - - Audio download path - Path to store downloaded audio in - Enter download path for audio files - - Autoplay - Automatically plays a video when NewPipe is called from another app - Default resolution - Default popup resolution - Show higher resolutions - Only some devices support playing 2K/4K videos - Play with Kodi - Kore app not found. Install it? - org.xbmc.kore - Show \"Play with Kodi\" option - Display an option to play a video via Kodi media center - Audio - Default audio format - Default video format - WebM — free format - M4A — better quality - Theme - Light - Dark - Black - Remember popup size and position - Remember last size and position of popup - Use fast inexact seek - Inexact seek allows the player to seek to positions faster with reduced precision - Load thumbnails - Disable to stop all thumbnails from loading and save on data and memory usage. Changing this will clear both in-memory and on-disk image cache. - Image cache wiped - Wipe cached metadata - Remove all cached webpage data - Metadata cache wiped - Auto-queue next stream - Automatically append a related stream when playback starts on the last stream in a non-repeating play queue. - Player gesture controls - Use gestures to control the brightness and volume of the player - Search suggestions - Show suggestions when searching - Search history - Store search queries locally - History - Keep track of watched videos - Resume on focus gain - Continue playing after interruptions (e.g. phone calls) - Download - Next video - Show next and similar videos - Show hold to append tip - Show tip when background or popup button is pressed on video details page - URL not supported - Default content country - Service - Default content language - Player - Behavior - Video & Audio - History & Cache - Popup - Appearance - Other - Debug - Playing in background - Playing in popup mode - Queued on background player - Queued on popup player - https://www.c3s.cc/ - Play - Content - Show age restricted content - Age Restricted Video. Allowing such material is possible from Settings. - live - LIVE - Downloads - Downloads - Error report - All - Channel - Playlist - Yes - Later - Disabled - Filter - Refresh - Clear - Resizing - Best resolution - Undo - Play All - Always - Just Once - File - - newpipe - NewPipe Notification - Notifications for NewPipe Background and Popup Players - - [Unknown] - - Toggle Orientation - Switch to Background - Switch to Popup - Switch to Main - - Import database - Export database - Will override your current history and subscriptions - Export history, subscriptions and playlists. - - Error - Network error - Could not load all thumbnails - Could not decrypt video URL signature - Could not parse website - Could not parse website completely - Content not available - Blocked by GEMA - Could not set up download menu - This is a LIVE STREAM, which is not yet supported. - Could not get any stream - Could not load image - App/UI crashed - Failed to play this stream - Unrecoverable player error occurred - Recovering from player error - External players don\'t support these types of links - Invalid URL - No video streams found - No audio streams found - Invalid directory - Invalid file/content source - File doesn\'t exist or insufficient permission to read or write to it - File name cannot be empty - An error occurred: %1$s - No streams available to download - - - Sorry, that should not have happened. - Guru Meditation. - Report error via e-mail - Sorry, some errors occurred. - REPORT - Info: - What happened: - What:\\nRequest:\\nContent Lang:\\nService:\\nGMT Time:\\nPackage:\\nVersion:\\nOS version: - Your comment (in English): - Details: - - - - Video preview thumbnail - Video preview thumbnail - Uploader\'s avatar thumbnail - Likes - Dislikes - Use Tor - (Experimental) Force download traffic through Tor for increased privacy (streaming videos not yet supported). - Report an Error - User report - No results - @string/no_videos - Nothing Here But Crickets - Drag to reorder - - Cannot create download directory \'%1$s\' - Created download directory \'%1$s\' - - Video - Audio - Retry - Storage access permission denied - Use old player - Old built-in Mediaframework player - - K - M - B - - - No subscribers - - %s subscriber - %s subscribers - - - No views - - %s view - %s views - - - No videos - - %s video - %s videos - - - - Start - Pause - Play - Create - Delete - Delete One - Delete All - Checksum - Dismiss - Rename - - - New mission - OK - - - Filename - Threads - Error - Server unsupported - File already exists - Malformed URL or Internet not available - NewPipe Downloading - Tap for details - Please wait… - Copied to clipboard - Please select an available download folder - This permission is needed to\nopen in popup mode - - - MD5 - SHA-1 - reCAPTCHA - reCAPTCHA Challenge - reCAPTCHA Challenge requested - - - - - Download - Allowed characters in filenames - Invalid characters are replaced with this value - Replacement character - - [^\\w\\d]+ - [\\n\\r|\\?*<":>/']+ - Letters and digits - Most special characters - - No player has been found for this file - - - About NewPipe - Settings - About - Third-party Licenses - © %1$s by %2$s under %3$s - Could not load license - Open website - About - Contributors - Licenses - A free lightweight YouTube frontend for Android. - Contribute - Whether you have ideas of; translation, design changes, code cleaning, or real heavy code changes—help is always welcome. The more is done the better it gets! - https://github.com/TeamNewPipe/NewPipe - View on GitHub - Donate - NewPipe gets developed by volunteers which spend their free time to bring the best experience to you. Now it is time to give back to make sure our developers can make NewPipe even more better while enjoying a cup of java! - https://newpipe.schabi.org/donate - Give back - Website - To get more information and the latest news about NewPipe visit our website. - https://newpipe.schabi.org/ - NewPipe\'s License - NewPipe is Free Software: You can use, study share and improve it at your will. Specifically you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Read license - - - - History - Searched - Watched - History is disabled - History - The history is empty - History cleared - Item deleted - Do you want to delete this item from search history? - Do you want to delete this item from watch history? - Are you sure you want to delete all items from history? - Last Played - Most Played - - - Content of main page - Blank Page - Kiosk Page - Subscription Page - Feed Page - Channel Page - - @string/blank_page_summary - @string/kiosk_page_summary - @string/feed_page_summary - @string/subscription_page_summary - @string/channel_page_summary - - Select a channel - No channel subscribed yet - Select a kiosk - Export complete - Import complete - No valid ZIP file - Warning: Could not import all files. - This will override your current setup. - - - Kiosk - Trending - Top 50 - New & hot - %1$s/%2$s - - - Background Player - Popup Player - Remove - Details - Audio Settings - Hold To Enqueue - Enqueue on Background - Enqueue on Popup - Start Playing Here - Start Here on Background - Start Here on Popup - - - Open Drawer - Close Drawer - YouTube - SoundCloud - Something will come here soon ;D - - - - NewPipe - Preferred open action - Default action when opening content — %s - - Video player - Background player - Popup player - Always ask - - Getting info… - "The requested content is loading" - - - Create New Playlist - Delete Playlist - Rename Playlist - Name - Add To Playlist - Set as Playlist Thumbnail - - Bookmark Playlist - Remove Bookmark - - Do you want to delete this playlist? - Playlist successfully created - Added to playlist - Playlist thumbnail changed - Failed to delete playlist - - - No Caption - - FIT - FILL - ZOOM - - Auto-generated - - - Caption - Modify player caption text scale and background styles. Require player restart to take effect. - - - Enable LeakCanary - Memory leak monitoring may cause app to become unresponsive when heap dumping - - Report Out-of-lifecycle errors - Force reporting of undeliverable Rx exceptions occurring outside of fragment or activity lifecycle after dispose - - - Import/Export - Import - Import from - Export to - - Importing… - Exporting… - - Import file - Previous export - - Subscriptions import failed - Subscriptions export failed - - To import your YouTube subscriptions you will need the export file, which can be downloaded following these instructions:\n\n1. Go to this url: %1$s\n2. Log in to your account when asked\n3. A download should start (that\'s the export file) - To import your SoundCloud followings you have to know your profile url or id. If you do, just type either of them in the input below and you\'re ready to go.\n\nIf you don\'t, you can follow these steps:\n\n1. Enable \"desktop mode\" in some browser (the site is not available for mobile devices)\n2. Go to this url: %1$s\n3. Log in to your account when asked\n4. Copy the url that you were redirected to (that\'s your profile url) - yourid, soundcloud.com/yourid - - Keep in mind that this operation can be network expensive.\n\nDo you want to continue? - - - Playback Speed Control - Tempo - Pitch - Unhook (may cause distortion) - Nightcore - Default -