mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-29 04:03:09 -05:00
Initial download queue fragment. Update progress working
This commit is contained in:
parent
3b9f4cb6f1
commit
999cc0df6e
15 changed files with 374 additions and 27 deletions
|
@ -12,11 +12,11 @@ import java.io.FileOutputStream;
|
|||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import eu.kanade.mangafeed.data.models.Chapter;
|
||||
import eu.kanade.mangafeed.data.models.Download;
|
||||
import eu.kanade.mangafeed.data.models.DownloadQueue;
|
||||
import eu.kanade.mangafeed.data.models.Manga;
|
||||
import eu.kanade.mangafeed.data.models.Page;
|
||||
import eu.kanade.mangafeed.events.DownloadChapterEvent;
|
||||
|
@ -37,7 +37,9 @@ public class DownloadManager {
|
|||
private PreferencesHelper preferences;
|
||||
private Gson gson;
|
||||
|
||||
private List<Download> queue;
|
||||
private DownloadQueue queue;
|
||||
|
||||
public static final String PAGE_LIST_FILE = "index.json";
|
||||
|
||||
public DownloadManager(Context context, SourceManager sourceManager, PreferencesHelper preferences) {
|
||||
this.context = context;
|
||||
|
@ -45,7 +47,7 @@ public class DownloadManager {
|
|||
this.preferences = preferences;
|
||||
this.gson = new Gson();
|
||||
|
||||
queue = new ArrayList<>();
|
||||
queue = new DownloadQueue();
|
||||
|
||||
initializeDownloadSubscription();
|
||||
}
|
||||
|
@ -78,7 +80,7 @@ public class DownloadManager {
|
|||
final Source source = sourceManager.get(event.getManga().source);
|
||||
|
||||
// If the chapter is already queued, don't add it again
|
||||
for (Download download : queue) {
|
||||
for (Download download : queue.get()) {
|
||||
if (download.chapter.id == event.getChapter().id)
|
||||
return true;
|
||||
}
|
||||
|
@ -119,7 +121,10 @@ public class DownloadManager {
|
|||
.pullPageListFromNetwork(download.chapter.url)
|
||||
.subscribeOn(Schedulers.io())
|
||||
// Add resulting pages to download object
|
||||
.doOnNext(pages -> download.pages = pages)
|
||||
.doOnNext(pages -> {
|
||||
download.pages = pages;
|
||||
download.setStatus(Download.DOWNLOADING);
|
||||
})
|
||||
// Get all the URLs to the source images, fetch pages if necessary
|
||||
.flatMap(pageList -> Observable.merge(
|
||||
Observable.from(pageList).filter(page -> page.getImageUrl() != null),
|
||||
|
@ -127,7 +132,7 @@ public class DownloadManager {
|
|||
// Start downloading images, consider we can have downloaded images already
|
||||
.concatMap(page -> getDownloadedImage(page, download.source, download.directory))
|
||||
// Remove from the queue
|
||||
.doOnCompleted(() -> removeFromQueue(download));
|
||||
.doOnCompleted(() -> onChapterDownloaded(download));
|
||||
}
|
||||
|
||||
// Get downloaded image if exists, otherwise download it with the method below
|
||||
|
@ -179,15 +184,15 @@ public class DownloadManager {
|
|||
return imagePath.exists() && !imagePath.isDirectory();
|
||||
}
|
||||
|
||||
private void removeFromQueue(final Download download) {
|
||||
private void onChapterDownloaded(final Download download) {
|
||||
download.setStatus(Download.DOWNLOADED);
|
||||
savePageList(download.source, download.manga, download.chapter, download.pages);
|
||||
queue.remove(download);
|
||||
}
|
||||
|
||||
// Return the page list from the chapter's directory if it exists, null otherwise
|
||||
public List<Page> getSavedPageList(Source source, Manga manga, Chapter chapter) {
|
||||
File chapterDir = getAbsoluteChapterDirectory(source, manga, chapter);
|
||||
File pagesFile = new File(chapterDir, "index.json");
|
||||
File pagesFile = new File(chapterDir, PAGE_LIST_FILE);
|
||||
|
||||
try {
|
||||
JsonReader reader = new JsonReader(new FileReader(pagesFile.getAbsolutePath()));
|
||||
|
@ -202,7 +207,7 @@ public class DownloadManager {
|
|||
// Save the page list to the chapter's directory
|
||||
public void savePageList(Source source, Manga manga, Chapter chapter, List<Page> pages) {
|
||||
File chapterDir = getAbsoluteChapterDirectory(source, manga, chapter);
|
||||
File pagesFile = new File(chapterDir, "index.json");
|
||||
File pagesFile = new File(chapterDir, PAGE_LIST_FILE);
|
||||
|
||||
FileOutputStream out;
|
||||
try {
|
||||
|
@ -230,4 +235,8 @@ public class DownloadManager {
|
|||
File path = getAbsoluteChapterDirectory(source, manga, chapter);
|
||||
DiskUtils.deleteFiles(path);
|
||||
}
|
||||
|
||||
public DownloadQueue getQueue() {
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.io.File;
|
|||
import java.util.List;
|
||||
|
||||
import eu.kanade.mangafeed.sources.base.Source;
|
||||
import rx.subjects.PublishSubject;
|
||||
|
||||
public class Download {
|
||||
public Source source;
|
||||
|
@ -12,9 +13,38 @@ public class Download {
|
|||
public List<Page> pages;
|
||||
public File directory;
|
||||
|
||||
public transient volatile int totalProgress;
|
||||
private transient volatile int status;
|
||||
|
||||
private transient PublishSubject<Download> statusSubject;
|
||||
|
||||
public static final int QUEUE = 0;
|
||||
public static final int DOWNLOADING = 1;
|
||||
public static final int DOWNLOADED = 2;
|
||||
public static final int ERROR = 3;
|
||||
|
||||
|
||||
public Download(Source source, Manga manga, Chapter chapter) {
|
||||
this.source = source;
|
||||
this.manga = manga;
|
||||
this.chapter = chapter;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
notifyStatus();
|
||||
}
|
||||
|
||||
public void setStatusSubject(PublishSubject<Download> subject) {
|
||||
this.statusSubject = subject;
|
||||
}
|
||||
|
||||
private void notifyStatus() {
|
||||
if (statusSubject != null)
|
||||
statusSubject.onNext(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package eu.kanade.mangafeed.data.models;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.subjects.PublishSubject;
|
||||
|
||||
public class DownloadQueue {
|
||||
|
||||
private List<Download> queue;
|
||||
private PublishSubject<Download> statusSubject;
|
||||
|
||||
public DownloadQueue() {
|
||||
queue = new ArrayList<>();
|
||||
statusSubject = PublishSubject.create();
|
||||
}
|
||||
|
||||
public void add(Download download) {
|
||||
download.setStatusSubject(statusSubject);
|
||||
queue.add(download);
|
||||
}
|
||||
|
||||
public void remove(Download download) {
|
||||
queue.remove(download);
|
||||
download.setStatusSubject(null);
|
||||
}
|
||||
|
||||
public List<Download> get() {
|
||||
return queue;
|
||||
}
|
||||
|
||||
public Observable<Download> getActiveDownloads() {
|
||||
return Observable.from(queue)
|
||||
.filter(download -> download.getStatus() == Download.DOWNLOADING);
|
||||
}
|
||||
|
||||
public Observable<Download> getStatusObservable() {
|
||||
return statusSubject
|
||||
.startWith(getActiveDownloads());
|
||||
}
|
||||
|
||||
}
|
|
@ -9,8 +9,8 @@ public class Page implements NetworkHelper.ProgressListener {
|
|||
private String url;
|
||||
private String imageUrl;
|
||||
private String imagePath;
|
||||
private transient int status;
|
||||
private transient int progress;
|
||||
private transient volatile int status;
|
||||
private transient volatile int progress;
|
||||
|
||||
private transient BehaviorSubject<Integer> statusSubject;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import eu.kanade.mangafeed.data.services.LibraryUpdateService;
|
|||
import eu.kanade.mangafeed.injection.module.AppModule;
|
||||
import eu.kanade.mangafeed.injection.module.DataModule;
|
||||
import eu.kanade.mangafeed.presenter.CataloguePresenter;
|
||||
import eu.kanade.mangafeed.presenter.DownloadQueuePresenter;
|
||||
import eu.kanade.mangafeed.presenter.LibraryPresenter;
|
||||
import eu.kanade.mangafeed.presenter.MangaChaptersPresenter;
|
||||
import eu.kanade.mangafeed.presenter.MangaDetailPresenter;
|
||||
|
@ -37,6 +38,7 @@ public interface AppComponent {
|
|||
void inject(MangaInfoPresenter mangaInfoPresenter);
|
||||
void inject(MangaChaptersPresenter mangaChaptersPresenter);
|
||||
void inject(ReaderPresenter readerPresenter);
|
||||
void inject(DownloadQueuePresenter downloadQueuePresenter);
|
||||
|
||||
void inject(ReaderActivity readerActivity);
|
||||
void inject(SettingsAccountsFragment settingsAccountsFragment);
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package eu.kanade.mangafeed.presenter;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import eu.kanade.mangafeed.data.helpers.DownloadManager;
|
||||
import eu.kanade.mangafeed.data.models.Download;
|
||||
import eu.kanade.mangafeed.data.models.DownloadQueue;
|
||||
import eu.kanade.mangafeed.data.models.Page;
|
||||
import eu.kanade.mangafeed.ui.fragment.DownloadQueueFragment;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class DownloadQueuePresenter extends BasePresenter<DownloadQueueFragment> {
|
||||
|
||||
@Inject DownloadManager downloadManager;
|
||||
|
||||
private DownloadQueue downloadQueue;
|
||||
private Subscription statusSubscription;
|
||||
private HashMap<Download, Subscription> progressSubscriptions;
|
||||
|
||||
public final static int GET_DOWNLOAD_QUEUE = 1;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
|
||||
downloadQueue = downloadManager.getQueue();
|
||||
progressSubscriptions = new HashMap<>();
|
||||
|
||||
restartableLatestCache(GET_DOWNLOAD_QUEUE,
|
||||
() -> Observable.just(downloadQueue.get()),
|
||||
DownloadQueueFragment::onNextDownloads,
|
||||
(view, error) -> Timber.e(error.getMessage()));
|
||||
|
||||
if (savedState == null)
|
||||
start(GET_DOWNLOAD_QUEUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTakeView(DownloadQueueFragment view) {
|
||||
super.onTakeView(view);
|
||||
|
||||
statusSubscription = downloadQueue.getStatusObservable()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(download -> {
|
||||
processStatus(download, view);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDropView() {
|
||||
destroySubscriptions();
|
||||
super.onDropView();
|
||||
}
|
||||
|
||||
private void processStatus(Download download, DownloadQueueFragment view) {
|
||||
switch (download.getStatus()) {
|
||||
case Download.DOWNLOADING:
|
||||
observeProgress(download, view);
|
||||
break;
|
||||
case Download.DOWNLOADED:
|
||||
unsubscribeProgress(download);
|
||||
download.totalProgress = download.pages.size() * 100;
|
||||
view.updateProgress(download);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void observeProgress(Download download, DownloadQueueFragment view) {
|
||||
Subscription subscription = Observable.interval(50, TimeUnit.MILLISECONDS, Schedulers.newThread())
|
||||
.flatMap(tick -> Observable.from(download.pages)
|
||||
.map(Page::getProgress)
|
||||
.reduce((x, y) -> x + y))
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(progress -> {
|
||||
download.totalProgress = progress;
|
||||
view.updateProgress(download);
|
||||
});
|
||||
|
||||
progressSubscriptions.put(download, subscription);
|
||||
}
|
||||
|
||||
private void unsubscribeProgress(Download download) {
|
||||
Subscription subscription = progressSubscriptions.remove(download);
|
||||
if (subscription != null)
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
|
||||
private void destroySubscriptions() {
|
||||
for (Subscription subscription : progressSubscriptions.values()) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
progressSubscriptions.clear();
|
||||
|
||||
remove(statusSubscription);
|
||||
}
|
||||
|
||||
}
|
|
@ -128,7 +128,7 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
|
|||
.toList()
|
||||
.flatMap(db::insertChapters)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnCompleted( () -> remove(markReadSubscription) )
|
||||
.doOnCompleted(() -> remove(markReadSubscription))
|
||||
.subscribe(result -> {
|
||||
}));
|
||||
}
|
||||
|
@ -137,21 +137,10 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
|
|||
add(downloadSubscription = selectedChapters
|
||||
.doOnCompleted(() -> remove(downloadSubscription))
|
||||
.subscribe(chapter -> {
|
||||
EventBus.getDefault().post(
|
||||
new DownloadChapterEvent(manga, chapter));
|
||||
EventBus.getDefault().post(new DownloadChapterEvent(manga, chapter));
|
||||
}));
|
||||
}
|
||||
|
||||
public void checkIsChapterDownloaded(Chapter chapter) {
|
||||
File dir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter);
|
||||
|
||||
if (dir.exists() && dir.listFiles().length > 0) {
|
||||
chapter.downloaded = Chapter.DOWNLOADED;
|
||||
} else {
|
||||
chapter.downloaded = Chapter.NOT_DOWNLOADED;
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteChapters(Observable<Chapter> selectedChapters) {
|
||||
deleteSubscription = selectedChapters
|
||||
.doOnCompleted( () -> remove(deleteSubscription) )
|
||||
|
@ -160,4 +149,16 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
|
|||
chapter.downloaded = Chapter.NOT_DOWNLOADED;
|
||||
});
|
||||
}
|
||||
|
||||
public void checkIsChapterDownloaded(Chapter chapter) {
|
||||
File dir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter);
|
||||
File pageList = new File(dir, DownloadManager.PAGE_LIST_FILE);
|
||||
|
||||
if (dir.exists() && dir.listFiles().length > 0 && pageList.exists()) {
|
||||
chapter.downloaded = Chapter.DOWNLOADED;
|
||||
} else {
|
||||
chapter.downloaded = Chapter.NOT_DOWNLOADED;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import butterknife.Bind;
|
|||
import butterknife.ButterKnife;
|
||||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.ui.activity.base.BaseActivity;
|
||||
import eu.kanade.mangafeed.ui.fragment.DownloadQueueFragment;
|
||||
import eu.kanade.mangafeed.ui.fragment.LibraryFragment;
|
||||
import eu.kanade.mangafeed.ui.fragment.SourceFragment;
|
||||
|
||||
|
@ -51,6 +52,9 @@ public class MainActivity extends BaseActivity {
|
|||
new PrimaryDrawerItem()
|
||||
.withName(R.string.catalogues_title)
|
||||
.withIdentifier(R.id.nav_drawer_catalogues),
|
||||
new PrimaryDrawerItem()
|
||||
.withName(R.string.download_title)
|
||||
.withIdentifier(R.id.nav_drawer_downloads),
|
||||
new PrimaryDrawerItem()
|
||||
.withName(R.string.settings_title)
|
||||
.withIdentifier(R.id.nav_drawer_settings)
|
||||
|
@ -70,6 +74,9 @@ public class MainActivity extends BaseActivity {
|
|||
case R.id.nav_drawer_catalogues:
|
||||
setFragment(SourceFragment.newInstance());
|
||||
break;
|
||||
case R.id.nav_drawer_downloads:
|
||||
setFragment(DownloadQueueFragment.newInstance());
|
||||
break;
|
||||
case R.id.nav_drawer_settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package eu.kanade.mangafeed.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
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 java.util.List;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.data.models.Download;
|
||||
import eu.kanade.mangafeed.presenter.DownloadQueuePresenter;
|
||||
import eu.kanade.mangafeed.ui.fragment.base.BaseRxFragment;
|
||||
import eu.kanade.mangafeed.ui.holder.DownloadHolder;
|
||||
import nucleus.factory.RequiresPresenter;
|
||||
import uk.co.ribot.easyadapter.EasyRecyclerAdapter;
|
||||
|
||||
@RequiresPresenter(DownloadQueuePresenter.class)
|
||||
public class DownloadQueueFragment extends BaseRxFragment<DownloadQueuePresenter> {
|
||||
|
||||
@Bind(R.id.download_list) RecyclerView downloadList;
|
||||
private EasyRecyclerAdapter<Download> adapter;
|
||||
|
||||
public static DownloadQueueFragment newInstance() {
|
||||
return new DownloadQueueFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
View view = inflater.inflate(R.layout.fragment_download_queue, container, false);
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
setToolbarTitle(R.string.download_title);
|
||||
|
||||
downloadList.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
createAdapter();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void createAdapter() {
|
||||
adapter = new EasyRecyclerAdapter<>(getActivity(), DownloadHolder.class);
|
||||
downloadList.setAdapter(adapter);
|
||||
}
|
||||
|
||||
public void onNextDownloads(List<Download> downloads) {
|
||||
adapter.setItems(downloads);
|
||||
}
|
||||
|
||||
// TODO use a better approach
|
||||
public void updateProgress(Download download) {
|
||||
for (int i = 0; i < adapter.getItems().size(); i++) {
|
||||
if (adapter.getItem(i) == download) {
|
||||
adapter.notifyItemChanged(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,6 @@ package eu.kanade.mangafeed.ui.fragment;
|
|||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
|
@ -41,7 +40,7 @@ public class MangaChaptersFragment extends BaseRxFragment<MangaChaptersPresenter
|
|||
|
||||
private ActionMode actionMode;
|
||||
|
||||
public static Fragment newInstance() {
|
||||
public static MangaChaptersFragment newInstance() {
|
||||
return new MangaChaptersFragment();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package eu.kanade.mangafeed.ui.holder;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.data.models.Download;
|
||||
import uk.co.ribot.easyadapter.ItemViewHolder;
|
||||
import uk.co.ribot.easyadapter.PositionInfo;
|
||||
import uk.co.ribot.easyadapter.annotations.LayoutId;
|
||||
import uk.co.ribot.easyadapter.annotations.ViewId;
|
||||
|
||||
@LayoutId(R.layout.item_download)
|
||||
public class DownloadHolder extends ItemViewHolder<Download> {
|
||||
|
||||
@ViewId(R.id.download_title) TextView downloadTitle;
|
||||
@ViewId(R.id.download_progress) ProgressBar downloadProgress;
|
||||
|
||||
public DownloadHolder(View view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetValues(Download download, PositionInfo positionInfo) {
|
||||
downloadTitle.setText(download.chapter.name);
|
||||
|
||||
if (download.pages == null) {
|
||||
downloadProgress.setProgress(0);
|
||||
} else {
|
||||
downloadProgress.setMax(download.pages.size() * 100);
|
||||
downloadProgress.setProgress(download.totalProgress);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
13
app/src/main/res/layout/fragment_download_queue.xml
Normal file
13
app/src/main/res/layout/fragment_download_queue.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/download_list">
|
||||
|
||||
</android.support.v7.widget.RecyclerView>
|
||||
|
||||
</LinearLayout>
|
32
app/src/main/res/layout/item_download.xml
Normal file
32
app/src/main/res/layout/item_download.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginRight="15dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:id="@+id/download_title"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/download_progress" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/download_progress_text"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -4,4 +4,5 @@
|
|||
<item name="nav_drawer_recent_updates" type="id">nav_drawer_recent_updates</item>
|
||||
<item name="nav_drawer_catalogues" type="id">nav_drawer_catalogues</item>
|
||||
<item name="nav_drawer_settings" type="id">nav_drawer_settings</item>
|
||||
<item name="nav_drawer_downloads" type="id">nav_drawer_downloads</item>
|
||||
</resources>
|
|
@ -93,5 +93,6 @@
|
|||
<string name="notification_no_new_chapters">No new chapters found</string>
|
||||
<string name="notification_new_chapters">Found new chapters for:</string>
|
||||
<string name="pref_download_threads">Download threads</string>
|
||||
<string name="download_title">Download queue</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue