Skip to content

Commit

Permalink
Merge pull request #597 from anthonycr/dev
Browse files Browse the repository at this point in the history
Version 4.5.1
anthonycr authored Jun 29, 2017
2 parents 931b0a3 + d7d2a58 commit e00bb88
Showing 116 changed files with 2,033 additions and 1,315 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@ jdk:
android:
components:
- tools
- build-tools-25.0.3
- android-25
- build-tools-26.0.0
- android-26
- extra-android-support
- extra-android-m2repository
licenses:
@@ -18,4 +18,5 @@ before_install:
install:
- ./gradlew
script:
- ./gradlew assembleDebug --stacktrace
- ./gradlew :app:assembleDebug --stacktrace
- ./gradlew :app:test --stacktrace
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
Change Log
==========

Version 4.5.1 *(2017-06-28)*
----------------------------
- Fixed bug with folders disappearing on bookmark homepage
- Updated history page
- Updated bookmark page
- Updating target to Android O
- Updating default bookmark favicons
- Fixed occasional bug with bookmark long press
- Updated downloads page design
- Enhanced keyboard shortcuts
- Fixed bug in google search suggestions for certain languages

Version 4.5.0 *(2017-06-08)*
----------------------------
- Translation updates
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -4,13 +4,10 @@
![](ic_launcher_small.png)

#### Download
* [Download APK from here](https://github.com/anthonycr/Lightning-Browser/releases)

* [Download from F-Droid](https://f-droid.org/repository/browse/?fdfilter=lightning&fdid=acr.browser.lightning)

* [Download Free from Google Play](https://play.google.com/store/apps/details?id=acr.browser.barebones)

* [Download Paid from Google Play](https://play.google.com/store/apps/details?id=acr.browser.lightning)
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/app/acr.browser.lightning) [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play" height="80">](https://play.google.com/store/apps/details?id=acr.browser.lightning)

#### Master Branch
* [![Build Status](https://travis-ci.org/anthonycr/Lightning-Browser.svg?branch=master)](https://travis-ci.org/anthonycr/Lightning-Browser)
15 changes: 10 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'com.getkeepsafe.dexcount'

android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
compileSdkVersion project.targetSdkVersion
buildToolsVersion project.buildToolsVersion

defaultConfig {
minSdkVersion 14
targetSdkVersion 25
minSdkVersion project.minSdkVersion
targetSdkVersion project.targetSdkVersion
versionName project.versionName
vectorDrawables.useSupportLibrary = true
}
@@ -63,9 +64,10 @@ dexcount {
}

dependencies {
testCompile 'junit:junit:4.12'

// support libraries
def supportLibVersion = '25.3.1'
def supportLibVersion = '25.4.0'
compile "com.android.support:palette-v7:$supportLibVersion"
compile "com.android.support:appcompat-v7:$supportLibVersion"
compile "com.android.support:design:$supportLibVersion"
@@ -107,4 +109,7 @@ dependencies {
def leakCanaryVersion = '1.5.1'
debugCompile "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"

// Kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
121 changes: 85 additions & 36 deletions app/src/LightningPlus/assets/hosts.txt

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
android:required="false"/>

<application
android:name=".app.BrowserApp"
android:name=".BrowserApp"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
@@ -38,9 +38,9 @@
android:value="2.1"/>

<activity
android:name=".activity.MainActivity"
android:name=".MainActivity"
android:alwaysRetainTaskState="true"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboardHidden|keyboard"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.LightTheme"
@@ -122,8 +122,8 @@
</intent-filter>
</activity>
<activity
android:name=".activity.SettingsActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:name=".settings.activity.SettingsActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboardHidden|keyboard"
android:label="@string/settings"
android:theme="@style/Theme.SettingsTheme">
<intent-filter>
@@ -133,9 +133,9 @@
</intent-filter>
</activity>
<activity
android:name=".activity.IncognitoActivity"
android:name=".IncognitoActivity"
android:alwaysRetainTaskState="true"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboardHidden|keyboard"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.DarkTheme"
@@ -147,8 +147,8 @@
</intent-filter>
</activity>
<activity
android:name=".activity.ReadingActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:name=".reading.activity.ReadingActivity"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboardHidden|keyboard"
android:label="@string/reading_mode"
android:theme="@style/Theme.SettingsTheme">
<intent-filter>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.app;
package acr.browser.lightning;

import android.app.Activity;
import android.app.Application;
@@ -20,11 +20,13 @@

import javax.inject.Inject;

import acr.browser.lightning.BuildConfig;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.database.bookmark.BookmarkExporter;
import acr.browser.lightning.database.bookmark.legacy.LegacyBookmarkManager;
import acr.browser.lightning.database.bookmark.BookmarkModel;
import acr.browser.lightning.database.bookmark.legacy.LegacyBookmarkManager;
import acr.browser.lightning.di.AppComponent;
import acr.browser.lightning.di.AppModule;
import acr.browser.lightning.di.DaggerAppComponent;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.FileUtils;
import acr.browser.lightning.utils.MemoryLeakUtils;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.activity;
package acr.browser.lightning;

import android.content.Intent;
import android.os.Build;
@@ -12,7 +12,7 @@
import com.anthonycr.bonsai.CompletableAction;
import com.anthonycr.bonsai.CompletableSubscriber;

import acr.browser.lightning.R;
import acr.browser.lightning.browser.activity.BrowserActivity;

@SuppressWarnings("deprecation")
public class IncognitoActivity extends BrowserActivity {
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package acr.browser.lightning.activity;
package acr.browser.lightning;

import android.content.Intent;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.KeyEvent;
import android.view.Menu;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
@@ -12,7 +13,7 @@
import com.anthonycr.bonsai.CompletableAction;
import com.anthonycr.bonsai.CompletableSubscriber;

import acr.browser.lightning.R;
import acr.browser.lightning.browser.activity.BrowserActivity;

@SuppressWarnings("deprecation")
public class MainActivity extends BrowserActivity {
@@ -76,5 +77,22 @@ public void run() {
});
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_P:
// Open a new private window
if(event.isShiftPressed()) {
startActivity(new Intent(this, IncognitoActivity.class));
overridePendingTransition(R.anim.slide_up_in, R.anim.fade_out_scale);
return true;
}
break;
}
}
return super.dispatchKeyEvent(event);
}


}
Original file line number Diff line number Diff line change
@@ -40,11 +40,11 @@ protected void onPostCreate(Bundle savedInstanceState) {
getDelegate().onPostCreate(savedInstanceState);
}

ActionBar getSupportActionBar() {
protected final ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}

void setSupportActionBar(@Nullable Toolbar toolbar) {
protected final void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.utils;
package acr.browser.lightning.adblock;

import android.app.Application;
import android.content.res.AssetManager;
@@ -16,14 +16,18 @@
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Singleton;

import acr.browser.lightning.BuildConfig;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.StringBuilderUtils;
import acr.browser.lightning.utils.Utils;

@Singleton
public class AdBlock {
@@ -132,42 +136,16 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
String line;
long time = System.currentTimeMillis();

final List<String> domains = new ArrayList<>(1);

while ((line = reader.readLine()) != null) {
lineBuilder.append(line);

if (!StringBuilderUtils.isEmpty(lineBuilder) &&
!StringBuilderUtils.startsWith(lineBuilder, COMMENT)) {
StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V4, EMPTY);
StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V4_ALT, EMPTY);
StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V6, EMPTY);
StringBuilderUtils.replace(lineBuilder, TAB, EMPTY);

int comment = lineBuilder.indexOf(COMMENT);
if (comment >= 0) {
lineBuilder.replace(comment, lineBuilder.length(), EMPTY);
}

StringBuilderUtils.trim(lineBuilder);

if (!StringBuilderUtils.isEmpty(lineBuilder) &&
!StringBuilderUtils.equals(lineBuilder, LOCALHOST)) {
while (StringBuilderUtils.contains(lineBuilder, SPACE)) {
int space = lineBuilder.indexOf(SPACE);
StringBuilder partial = StringBuilderUtils.substring(lineBuilder, 0, space);
StringBuilderUtils.trim(partial);

String partialLine = partial.toString();
mBlockedDomainsList.add(partialLine);
StringBuilderUtils.replace(lineBuilder, partialLine, EMPTY);
StringBuilderUtils.trim(lineBuilder);
}
if (lineBuilder.length() > 0) {
mBlockedDomainsList.add(lineBuilder.toString());
}
}
}
parseString(lineBuilder, domains);
lineBuilder.setLength(0);
}

mBlockedDomainsList.addAll(domains);
Log.d(TAG, "Loaded ad list in: " + (System.currentTimeMillis() - time) + " ms");
} catch (IOException e) {
Log.wtf(TAG, "Reading blocked domains list from file '"
@@ -179,4 +157,41 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
});
}

private static void parseString(@NonNull StringBuilder lineBuilder, @NonNull List<String> parsedList) {
if (!StringBuilderUtils.isEmpty(lineBuilder) &&
!StringBuilderUtils.startsWith(lineBuilder, COMMENT)) {
StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V4, EMPTY);
StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V4_ALT, EMPTY);
StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V6, EMPTY);
StringBuilderUtils.replace(lineBuilder, TAB, EMPTY);

int comment = lineBuilder.indexOf(COMMENT);
if (comment >= 0) {
lineBuilder.replace(comment, lineBuilder.length(), EMPTY);
}

StringBuilderUtils.trim(lineBuilder);

if (!StringBuilderUtils.isEmpty(lineBuilder) &&
!StringBuilderUtils.equals(lineBuilder, LOCALHOST)) {
while (StringBuilderUtils.contains(lineBuilder, SPACE)) {
int space = lineBuilder.indexOf(SPACE);
StringBuilder partial = StringBuilderUtils.substring(lineBuilder, 0, space);
StringBuilderUtils.trim(partial);

String partialLine = partial.toString();

// Add string to list
parsedList.add(partialLine);
StringBuilderUtils.replace(lineBuilder, partialLine, EMPTY);
StringBuilderUtils.trim(lineBuilder);
}
if (lineBuilder.length() > 0) {
// Add string to list.
parsedList.add(lineBuilder.toString());
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package acr.browser.lightning.browser;

import android.app.Activity;
import android.app.Application;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.webkit.URLUtil;

import com.anthonycr.bonsai.CompletableOnSubscribe;
import com.anthonycr.bonsai.Schedulers;
@@ -14,9 +16,10 @@

import acr.browser.lightning.BuildConfig;
import acr.browser.lightning.R;
import acr.browser.lightning.activity.TabsManager;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.StartPage;
import acr.browser.lightning.controller.UIController;
import acr.browser.lightning.preference.PreferenceManager;

@@ -33,6 +36,7 @@ public class BrowserPresenter {
private static final String TAG = "BrowserPresenter";

@NonNull private final TabsManager mTabsModel;
@Inject Application mApplication;
@Inject PreferenceManager mPreferences;

@NonNull private final BrowserView mView;
@@ -116,7 +120,7 @@ private void onTabChanged(@Nullable LightningView newTab) {
mView.updateProgress(newTab.getProgress());
mView.setBackButtonEnabled(newTab.canGoBack());
mView.setForwardButtonEnabled(newTab.canGoForward());
mView.updateUrl(newTab.getUrl(), true);
mView.updateUrl(newTab.getUrl(), false);
mView.setTabView(newTab.getWebView());
int index = mTabsModel.indexOfTab(newTab);
if (index >= 0) {
@@ -143,6 +147,19 @@ public void closeAllOtherTabs() {

}

@NonNull
private String mapHomepageToCurrentUrl() {
String homepage = mPreferences.getHomepage();
switch (homepage) {
case Constants.SCHEME_HOMEPAGE:
return Constants.FILE + StartPage.getStartPageFile(mApplication);
case Constants.SCHEME_BOOKMARKS:
return Constants.FILE + BookmarkPage.getBookmarkPage(mApplication, null);
default:
return homepage;
}
}

/**
* Deletes the tab at the specified position.
*
@@ -165,8 +182,8 @@ public void deleteTab(int position) {
boolean shouldClose = mShouldClose && isShown && tabToDelete.isNewTab();
final LightningView currentTab = mTabsModel.getCurrentTab();
if (mTabsModel.size() == 1 && currentTab != null &&
(UrlUtils.isStartPageUrl(currentTab.getUrl()) ||
currentTab.getUrl().equals(mPreferences.getHomepage()))) {
URLUtil.isFileUrl(currentTab.getUrl()) &&
currentTab.getUrl().equals(mapHomepageToCurrentUrl())) {
mView.closeActivity();
return;
} else {
@@ -232,7 +249,7 @@ public void run() {
tab.loadUrl(url);
}
} else if (url != null) {
if (url.startsWith(Constants.FILE)) {
if (URLUtil.isFileUrl(url)) {
mView.showBlockedLocalFileDialog(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.view.View;

@@ -11,7 +12,7 @@ public interface BrowserView {

void removeTabView();

void updateUrl(String url, boolean shortUrl);
void updateUrl(@Nullable String url, boolean isLoading);

void updateProgress(int progress);

@@ -21,7 +22,7 @@ public interface BrowserView {

void closeActivity();

void showBlockedLocalFileDialog(DialogInterface.OnClickListener listener);
void showBlockedLocalFileDialog(@NonNull DialogInterface.OnClickListener listener);

void showSnackbar(@StringRes int resource);

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package acr.browser.lightning.browser;

import android.app.Application;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.UrlUtils;
import acr.browser.lightning.utils.Utils;

/**
* A UI model for the search box.
*/
public class SearchBoxModel {

@Inject PreferenceManager mPreferences;
@Inject Application mApplication;

@NonNull private final String mUntitledTitle;

@Inject
public SearchBoxModel() {
BrowserApp.getAppComponent().inject(this);
mUntitledTitle = mApplication.getString(R.string.untitled);
}

/**
* Returns the contents of the search box based on a variety of factors.
* <ul>
* <li>The user's preference to show either the URL, domain, or page title</li>
* <li>Whether or not the current page is loading</li>
* <li>Whether or not the current page is a Lightning generated page.</li>
* </ul>
* This method uses the URL, title, and loading information to determine what
* should be displayed by the search box.
*
* @param url the URL of the current page.
* @param title the title of the current page, if known.
* @param isLoading whether the page is currently loading or not.
* @return the string that should be displayed by the search box.
*/
@NonNull
public String getDisplayContent(@NonNull String url, @Nullable String title, boolean isLoading) {
if (UrlUtils.isSpecialUrl(url)) {
return "";
} else if (isLoading) {
return url;
} else {
switch (mPreferences.getUrlBoxContentChoice()) {
default:
case 0: // Default, show only the domain
String domain = Utils.getDomainName(url);
return domain != null ? domain : url;
case 1: // URL, show the entire URL
return url;
case 2: // Title, show the page's title
if (!TextUtils.isEmpty(title)) {
return title;
} else {
return mUntitledTitle;
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.activity;
package acr.browser.lightning.browser;

import android.app.Activity;
import android.app.Application;
@@ -12,6 +12,7 @@
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.URLUtil;
import android.webkit.WebView;

import com.anthonycr.bonsai.Completable;
@@ -30,9 +31,8 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.DownloadsPage;
import acr.browser.lightning.constant.HistoryPage;
import acr.browser.lightning.constant.StartPage;
@@ -174,15 +174,15 @@ public void onItem(@Nullable String item) {
});
} else if (UrlUtils.isDownloadsUrl(url)) {
new DownloadsPage().getDownloadsPage()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<String>() {
@Override
public void onItem(@Nullable String item) {
Preconditions.checkNonNull(item);
tab.loadUrl(item);
}
});
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<String>() {
@Override
public void onItem(@Nullable String item) {
Preconditions.checkNonNull(item);
tab.loadUrl(item);
}
});
} else if (UrlUtils.isStartPageUrl(url)) {
new StartPage().getHomepage()
.subscribeOn(Schedulers.io())
@@ -214,7 +214,7 @@ public void onItem(@Nullable String item) {
@Override
public void onComplete() {
if (url != null) {
if (url.startsWith(Constants.FILE)) {
if (URLUtil.isFileUrl(url)) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
Dialog dialog = builder.setCancelable(true)
.setTitle(R.string.title_warning)

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.activity;
package acr.browser.lightning.browser.activity;

import android.content.Intent;
import android.content.res.Configuration;
@@ -10,13 +10,14 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.ThemeUtils;

public abstract class ThemableBrowserActivity extends AppCompatActivity {

@Inject PreferenceManager mPreferences;
// TODO: 6/26/17 get rid fo protected reference
@Inject protected PreferenceManager mPreferences;

private int mTheme;
private boolean mShowTabsInDrawer;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.activity;
package acr.browser.lightning.browser.bookmark;

import android.support.annotation.Nullable;

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.fragment;
package acr.browser.lightning.browser.fragment;

import android.app.Activity;
import android.content.Context;
@@ -34,11 +34,11 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.activity.BookmarkUiModel;
import acr.browser.lightning.activity.ReadingActivity;
import acr.browser.lightning.activity.TabsManager;
import acr.browser.lightning.browser.bookmark.BookmarkUiModel;
import acr.browser.lightning.reading.activity.ReadingActivity;
import acr.browser.lightning.browser.TabsManager;
import acr.browser.lightning.animation.AnimationUtils;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.browser.BookmarksView;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.controller.UIController;
@@ -320,10 +320,10 @@ private void setBookmarkDataSet(@NonNull List<HistoryItem> items, boolean animat
}

private void setupNavigationButton(@NonNull View view, @IdRes int buttonId, @IdRes int imageId) {
FrameLayout frameButton = (FrameLayout) view.findViewById(buttonId);
FrameLayout frameButton = view.findViewById(buttonId);
frameButton.setOnClickListener(this);
frameButton.setOnLongClickListener(this);
ImageView buttonImage = (ImageView) view.findViewById(imageId);
ImageView buttonImage = view.findViewById(imageId);
buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
}

@@ -537,8 +537,8 @@ public void onBindViewHolder(final BookmarkViewHolder holder, int position) {
Subscription oldSubscription = mFaviconFetchSubscriptions.get(url);
SubscriptionUtils.safeUnsubscribe(oldSubscription);

final Subscription faviconSubscription = mFaviconModel.faviconForUrl(url, mWebpageBitmap, true)
.subscribeOn(Schedulers.worker())
final Subscription faviconSubscription = mFaviconModel.faviconForUrl(url, web.getTitle())
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<Bitmap>() {
@Override
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.fragment;
package acr.browser.lightning.browser.fragment;

import android.app.Activity;
import android.content.Context;
@@ -34,12 +34,12 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.activity.TabsManager;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.browser.TabsManager;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.browser.TabsView;
import acr.browser.lightning.controller.UIController;
import acr.browser.lightning.fragment.anim.HorizontalItemAnimator;
import acr.browser.lightning.fragment.anim.VerticalItemAnimator;
import acr.browser.lightning.browser.fragment.anim.HorizontalItemAnimator;
import acr.browser.lightning.browser.fragment.anim.VerticalItemAnimator;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.DrawableUtils;
import acr.browser.lightning.utils.ThemeUtils;
@@ -130,7 +130,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
} else {
view = inflater.inflate(R.layout.tab_strip, container, false);
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
ImageView newTab = (ImageView) view.findViewById(R.id.new_tab_button);
ImageView newTab = view.findViewById(R.id.new_tab_button);
newTab.setColorFilter(ThemeUtils.getIconDarkThemeColor(getActivity()));
newTab.setOnClickListener(new View.OnClickListener() {
@Override
@@ -183,7 +183,7 @@ private TabsManager getTabsManager() {
private void setupFrameLayoutButton(@NonNull final View root, @IdRes final int buttonId,
@IdRes final int imageId) {
final View frameButton = root.findViewById(buttonId);
final ImageView buttonImage = (ImageView) root.findViewById(imageId);
final ImageView buttonImage = root.findViewById(imageId);
frameButton.setOnClickListener(this);
frameButton.setOnLongClickListener(this);
buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
@@ -399,11 +399,11 @@ public class LightningViewHolder extends RecyclerView.ViewHolder implements View

public LightningViewHolder(@NonNull View view) {
super(view);
txtTitle = (TextView) view.findViewById(R.id.textTab);
favicon = (ImageView) view.findViewById(R.id.faviconTab);
exit = (ImageView) view.findViewById(R.id.deleteButton);
layout = (LinearLayout) view.findViewById(R.id.tab_item_background);
exitButton = (FrameLayout) view.findViewById(R.id.deleteAction);
txtTitle = view.findViewById(R.id.textTab);
favicon = view.findViewById(R.id.faviconTab);
exit = view.findViewById(R.id.deleteButton);
layout = view.findViewById(R.id.tab_item_background);
exitButton = view.findViewById(R.id.deleteAction);
exit.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);

exitButton.setOnClickListener(this);
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package acr.browser.lightning.fragment.anim;
package acr.browser.lightning.browser.fragment.anim;

import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package acr.browser.lightning.fragment.anim;
package acr.browser.lightning.browser.fragment.anim;

import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
151 changes: 100 additions & 51 deletions app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java
Original file line number Diff line number Diff line change
@@ -6,8 +6,10 @@
import android.app.Activity;
import android.app.Application;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import com.anthonycr.bonsai.Single;
import com.anthonycr.bonsai.SingleAction;
@@ -24,9 +26,11 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.database.bookmark.BookmarkModel;
import acr.browser.lightning.favicon.FaviconModel;
import acr.browser.lightning.favicon.FaviconUtils;
import acr.browser.lightning.utils.Preconditions;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
@@ -74,12 +78,27 @@ public final class BookmarkPage {
private static final String END = "</div></body></html>";

private static final String FOLDER_ICON = "folder.png";
private static final String DEFAULT_ICON = "default.png";

private File mFilesDir;
private File mCacheDir;
@NonNull
public static File getBookmarkPage(@NonNull Application application, @Nullable String folder) {
String prefix = !TextUtils.isEmpty(folder) ? folder + '-' : "";
return new File(application.getFilesDir(), prefix + FILENAME);
}

@NonNull
private static File getFaviconFile(@NonNull Application application) {
return new File(application.getCacheDir(), FOLDER_ICON);
}

@NonNull
private static File getDefaultIconFile(@NonNull Application application) {
return new File(application.getCacheDir(), DEFAULT_ICON);
}

@Inject Application mApp;
@Inject BookmarkModel mManager;
@Inject BookmarkModel mBookmarkModel;
@Inject FaviconModel mFaviconModel;

@NonNull private final Bitmap mFolderIcon;
@NonNull private final String mTitle;
@@ -95,26 +114,24 @@ public Single<String> getBookmarkPage() {
return Single.create(new SingleAction<String>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<String> subscriber) {
mCacheDir = mApp.getCacheDir();
mFilesDir = mApp.getFilesDir();
cacheDefaultFolderIcon();
cacheIcon(mFolderIcon, getFaviconFile(mApp));
cacheIcon(mFaviconModel.getDefaultBitmapForString(null), getDefaultIconFile(mApp));
buildBookmarkPage(null);

File bookmarkWebPage = new File(mFilesDir, FILENAME);
File bookmarkWebPage = getBookmarkPage(mApp, null);

subscriber.onItem(Constants.FILE + bookmarkWebPage);
subscriber.onComplete();
}
});
}

private void cacheDefaultFolderIcon() {
private void cacheIcon(@NonNull Bitmap icon, @NonNull File file) {
FileOutputStream outputStream = null;
File image = new File(mCacheDir, FOLDER_ICON);
try {
outputStream = new FileOutputStream(image);
mFolderIcon.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
mFolderIcon.recycle();
outputStream = new FileOutputStream(file);
icon.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
icon.recycle();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
@@ -123,52 +140,84 @@ private void cacheDefaultFolderIcon() {
}

private void buildBookmarkPage(@Nullable final String folder) {
mManager.getBookmarksFromFolderSorted(folder)
mBookmarkModel.getBookmarksFromFolderSorted(folder)
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override
public void onItem(@Nullable List<HistoryItem> list) {
public void onItem(@Nullable final List<HistoryItem> list) {
Preconditions.checkNonNull(list);

final File bookmarkWebPage;
if (folder == null || folder.isEmpty()) {
bookmarkWebPage = new File(mFilesDir, FILENAME);
if (folder == null) {
mBookmarkModel.getFoldersSorted()
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override
public void onItem(@Nullable List<HistoryItem> item) {
Preconditions.checkNonNull(item);

list.addAll(item);

buildPageHtml(list, null);
}
});
} else {
bookmarkWebPage = new File(mFilesDir, folder + '-' + FILENAME);
}
final StringBuilder bookmarkBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2);

final String folderIconPath = Constants.FILE + mCacheDir + '/' + FOLDER_ICON;
for (int n = 0, size = list.size(); n < size; n++) {
final HistoryItem item = list.get(n);
bookmarkBuilder.append(PART1);
if (item.isFolder()) {
final File folderPage = new File(mFilesDir, item.getTitle() + '-' + FILENAME);
bookmarkBuilder.append(Constants.FILE).append(folderPage);
bookmarkBuilder.append(PART2);
bookmarkBuilder.append(folderIconPath);
buildBookmarkPage(item.getTitle());
} else {
bookmarkBuilder.append(item.getUrl());
bookmarkBuilder.append(PART2).append(PART3);
bookmarkBuilder.append(item.getUrl());
}
bookmarkBuilder.append(PART4);
bookmarkBuilder.append(item.getTitle());
bookmarkBuilder.append(PART5);
}
bookmarkBuilder.append(END);
FileWriter bookWriter = null;
try {
//noinspection IOResourceOpenedButNotSafelyClosed
bookWriter = new FileWriter(bookmarkWebPage, false);
bookWriter.write(bookmarkBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
Utils.close(bookWriter);
buildPageHtml(list, folder);
}
}
});
}

private void buildPageHtml(@NonNull List<HistoryItem> bookmarksAndFolders, @Nullable String folder) {
final File bookmarkWebPage = getBookmarkPage(mApp, folder);

final StringBuilder bookmarkBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2);

final String folderIconPath = getFaviconFile(mApp).toString();

for (int n = 0, size = bookmarksAndFolders.size(); n < size; n++) {
final HistoryItem item = bookmarksAndFolders.get(n);
bookmarkBuilder.append(PART1);
if (item.isFolder()) {
final File folderPage = getBookmarkPage(mApp, item.getTitle());
bookmarkBuilder.append(Constants.FILE).append(folderPage);
bookmarkBuilder.append(PART2);
bookmarkBuilder.append(folderIconPath);
buildBookmarkPage(item.getTitle());
} else {

Uri bookmarkUri = FaviconUtils.safeUri(item.getUrl());

String faviconFileUrl;

if (bookmarkUri != null) {
File faviconFile = FaviconModel.getFaviconCacheFile(mApp, bookmarkUri);
if (!faviconFile.exists()) {
Bitmap defaultFavicon = mFaviconModel.getDefaultBitmapForString(item.getTitle());
mFaviconModel.cacheFaviconForUrl(defaultFavicon, item.getUrl()).subscribe();
}

faviconFileUrl = Constants.FILE + faviconFile;
} else {
faviconFileUrl = Constants.FILE + getDefaultIconFile(mApp);
}


bookmarkBuilder.append(item.getUrl());
bookmarkBuilder.append(PART2).append(faviconFileUrl);
}
bookmarkBuilder.append(PART4);
bookmarkBuilder.append(item.getTitle());
bookmarkBuilder.append(PART5);
}
bookmarkBuilder.append(END);
FileWriter bookWriter = null;
try {
//noinspection IOResourceOpenedButNotSafelyClosed
bookWriter = new FileWriter(bookmarkWebPage, false);
bookWriter.write(bookmarkBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
Utils.close(bookWriter);
}
}

}
Original file line number Diff line number Diff line change
@@ -30,9 +30,9 @@ private Constants() {
public static final String YANDEX_SEARCH = "https://yandex.ru/yandsearch?lr=21411&text=";

// Custom local page schemes
public static final String SCHEME_HOMEPAGE = "about:home";
public static final String SCHEME_BLANK = "about:blank";
public static final String SCHEME_BOOKMARKS = "about:bookmarks";
public static final String SCHEME_HOMEPAGE = Constants.ABOUT + "home";
public static final String SCHEME_BLANK = Constants.ABOUT + "blank";
public static final String SCHEME_BOOKMARKS = Constants.ABOUT + "bookmarks";

// Miscellaneous JavaScript
public static final String JAVASCRIPT_INVERT_PAGE = "javascript:(function(){var e='img {-webkit-filter: invert(100%);'+'-moz-filter: invert(100%);'+'-o-filter: invert(100%);'+'-ms-filter: invert(100%); }',t=document.getElementsByTagName('head')[0],n=document.createElement('style');if(!window.counter){window.counter=1}else{window.counter++;if(window.counter%2==0){var e='html {-webkit-filter: invert(0%); -moz-filter: invert(0%); -o-filter: invert(0%); -ms-filter: invert(0%); }'}}n.type='text/css';if(n.styleSheet){n.styleSheet.cssText=e}else{n.appendChild(document.createTextNode(e))}t.appendChild(n)})();";
31 changes: 17 additions & 14 deletions app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
import android.app.Application;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.anthonycr.bonsai.Single;
import com.anthonycr.bonsai.SingleAction;
@@ -20,7 +21,7 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.database.downloads.DownloadItem;
import acr.browser.lightning.database.downloads.DownloadsModel;
import acr.browser.lightning.preference.PreferenceManager;
@@ -29,9 +30,8 @@

public final class DownloadsPage {

/**
* The download page standard suffix
*/
private static final String TAG = "DownloadsPage";

public static final String FILENAME = "downloads.html";

private static final String HEADING_1 = "<!DOCTYPE html><html xmlns=http://www.w3.org/1999/xhtml>\n" +
@@ -41,10 +41,12 @@ public final class DownloadsPage {
"<meta name=viewport content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n" +
"<title>";

private static final String HEADING_2 = "</title>" +
"</head>" +
"<style>body{background:#f5f5f5;}.box{vertical-align:middle;position:relative; display: block; margin: 10px;padding:10px; background-color:#fff;box-shadow: 0px 2px 4px rgba( 0, 0, 0, 0.25 );font-family: Arial;color: #444;font-size: 12px;-moz-border-radius: 2px;-webkit-border-radius: 2px;border-radius: 2px;}.box a { width: 100%; height: 100%; position: absolute; left: 0; top: 0;}.black {color: black;font-size: 15px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}.font {color: gray;font-size: 10px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}</style>" +
"<body><div id='content'>";
private static final String HEADING_2 = "</title></head><style>body,html {margin: 0px; padding: 0px;}" +
".box { vertical-align:middle;position:relative; display: block; margin: 0px;padding-left:14px;padding-right:14px;padding-top:9px;padding-bottom:9px; background-color:#fff;border-bottom: 1px solid #d2d2d2;font-family: Arial;color: #444;font-size: 12px;}" +
".box a { width: 100%; height: 100%; position: absolute; left: 0; top: 0;}" +
".black {color: black;font-size: 15px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}" +
".font {color: gray;font-size: 10px;font-family: Arial; white-space: nowrap; overflow: hidden;margin:auto; text-overflow: ellipsis; -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis;}" +
"</style><body><div id=\"content\">";

private static final String PART1 = "<div class=box><a href='";

@@ -56,7 +58,10 @@ public final class DownloadsPage {

private static final String END = "</div></body></html>";

private File mFilesDir;
@NonNull
private static File getDownloadsPageFile(@NonNull Application application) {
return new File(application.getFilesDir(), FILENAME);
}

@Inject Application mApp;
@Inject PreferenceManager mPreferenceManager;
@@ -74,11 +79,9 @@ public Single<String> getDownloadsPage() {
return Single.create(new SingleAction<String>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<String> subscriber) {
mFilesDir = mApp.getFilesDir();

buildDownloadsPage();

File downloadsWebPage = new File(mFilesDir, FILENAME);
File downloadsWebPage = getDownloadsPageFile(mApp);

subscriber.onItem(Constants.FILE + downloadsWebPage);
subscriber.onComplete();
@@ -120,10 +123,10 @@ public void onItem(@Nullable List<DownloadItem> list) {
FileWriter bookWriter = null;
try {
//noinspection IOResourceOpenedButNotSafelyClosed
bookWriter = new FileWriter(new File(mFilesDir, FILENAME), false);
bookWriter = new FileWriter(getDownloadsPageFile(mApp), false);
bookWriter.write(downloadsBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Unable to write download page to disk", e);
} finally {
Utils.close(bookWriter);
}
21 changes: 17 additions & 4 deletions app/src/main/java/acr/browser/lightning/constant/HistoryPage.java
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.database.history.HistoryModel;
import acr.browser.lightning.utils.Preconditions;
@@ -61,9 +61,22 @@ public class HistoryPage {

private static final String END = "</div></body></html>";

/**
* Get the file that the history page is stored in
* or should be stored in.
*
* @param application the application used to access the file.
* @return a valid file object, note that the file might not exist.
*/
@NonNull
private static File getHistoryPageFile(@NonNull Application application) {
return new File(application.getFilesDir(), FILENAME);
}

@NonNull private final String mTitle;

@Inject Application mApp;
@Inject HistoryModel mHistoryModel;

public HistoryPage() {
BrowserApp.getAppComponent().inject(this);
@@ -77,7 +90,7 @@ public Single<String> getHistoryPage() {
public void onSubscribe(@NonNull final SingleSubscriber<String> subscriber) {
final StringBuilder historyBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2);

HistoryModel.lastHundredVisitedHistoryItems()
mHistoryModel.lastHundredVisitedHistoryItems()
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override
public void onItem(@Nullable List<HistoryItem> item) {
@@ -97,7 +110,7 @@ public void onItem(@Nullable List<HistoryItem> item) {
}

historyBuilder.append(END);
File historyWebPage = new File(mApp.getFilesDir(), FILENAME);
File historyWebPage = getHistoryPageFile(mApp);
FileWriter historyWriter = null;
try {
//noinspection IOResourceOpenedButNotSafelyClosed
@@ -130,7 +143,7 @@ public static Completable deleteHistoryPage(@NonNull final Application applicati
return Completable.create(new CompletableAction() {
@Override
public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
File historyWebPage = new File(application.getFilesDir(), FILENAME);
File historyWebPage = getHistoryPageFile(application);
if (historyWebPage.exists()) {
historyWebPage.delete();
}
133 changes: 35 additions & 98 deletions app/src/main/java/acr/browser/lightning/constant/StartPage.java
Original file line number Diff line number Diff line change
@@ -17,47 +17,53 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.search.SearchEngineProvider;
import acr.browser.lightning.search.engine.BaseSearchEngine;
import acr.browser.lightning.utils.Utils;

public class StartPage {

public static final String FILENAME = "homepage.html";

private static final String HEAD_1 = "<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<head>"
+ "<meta content=\"en-us\" http-equiv=\"Content-Language\" />"
+ "<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" />"
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">"
+ "<title>";
+ "<head>"
+ "<meta content=\"en-us\" http-equiv=\"Content-Language\" />"
+ "<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" />"
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">"
+ "<title>";

private static final String HEAD_2 = "</title>"
+ "</head>"
+ "<style>body{background:#f5f5f5;text-align:center;margin:0px;}#search_input{height:35px; "
+ "width:100%;outline:none;border:none;font-size: 16px;background-color:transparent;}"
+ "span { display: block; overflow: hidden; padding-left:5px;vertical-align:middle;}"
+ ".search_bar{display:table;vertical-align:middle;width:90%;height:35px;max-width:500px;margin:0 auto;background-color:#fff;box-shadow: 0px 2px 3px rgba( 0, 0, 0, 0.25 );"
+ "font-family: Arial;color: #444;-moz-border-radius: 2px;-webkit-border-radius: 2px;border-radius: 2px;}"
+ "#search_submit{outline:none;height:37px;float:right;color:#404040;font-size:16px;font-weight:bold;border:none;"
+ "background-color:transparent;}.outer { display: table; position: absolute; height: 100%; width: 100%;}"
+ ".middle { display: table-cell; vertical-align: middle;}.inner { margin-left: auto; margin-right: auto; "
+ "margin-bottom:10%; width: 100%;}img.smaller{width:50%;max-width:300px;}"
+ ".box { vertical-align:middle;position:relative; display: block; margin: 10px;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px;"
+ " background-color:#fff;box-shadow: 0px 3px rgba( 0, 0, 0, 0.1 );font-family: Arial;color: #444;"
+ "font-size: 12px;-moz-border-radius: 2px;-webkit-border-radius: 2px;"
+ "border-radius: 2px;}</style><body> <div class=\"outer\"><div class=\"middle\"><div class=\"inner\"><img class=\"smaller\" src=\"";
+ "</head>"
+ "<style>body{background:#f5f5f5;text-align:center;margin:0px;}#search_input{height:35px; "
+ "width:100%;outline:none;border:none;font-size: 16px;background-color:transparent;}"
+ "span { display: block; overflow: hidden; padding-left:5px;vertical-align:middle;}"
+ ".search_bar{display:table;vertical-align:middle;width:90%;height:35px;max-width:500px;margin:0 auto;background-color:#fff;box-shadow: 0px 2px 3px rgba( 0, 0, 0, 0.25 );"
+ "font-family: Arial;color: #444;-moz-border-radius: 2px;-webkit-border-radius: 2px;border-radius: 2px;}"
+ "#search_submit{outline:none;height:37px;float:right;color:#404040;font-size:16px;font-weight:bold;border:none;"
+ "background-color:transparent;}.outer { display: table; position: absolute; height: 100%; width: 100%;}"
+ ".middle { display: table-cell; vertical-align: middle;}.inner { margin-left: auto; margin-right: auto; "
+ "margin-bottom:10%; width: 100%;}img.smaller{width:50%;max-width:300px;}"
+ ".box { vertical-align:middle;position:relative; display: block; margin: 10px;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px;"
+ " background-color:#fff;box-shadow: 0px 3px rgba( 0, 0, 0, 0.1 );font-family: Arial;color: #444;"
+ "font-size: 12px;-moz-border-radius: 2px;-webkit-border-radius: 2px;"
+ "border-radius: 2px;}</style><body> <div class=\"outer\"><div class=\"middle\"><div class=\"inner\"><img class=\"smaller\" src=\"";

private static final String MIDDLE = "\" ></br></br><form onsubmit=\"return search()\" class=\"search_bar\" autocomplete=\"off\">"
+ "<input type=\"submit\" id=\"search_submit\" value=\"Search\" ><span><input class=\"search\" type=\"text\" value=\"\" id=\"search_input\" >"
+ "</span></form></br></br></div></div></div><script type=\"text/javascript\">function search(){if(document.getElementById(\"search_input\").value != \"\"){window.location.href = \"";
+ "<input type=\"submit\" id=\"search_submit\" value=\"Search\" ><span><input class=\"search\" type=\"text\" value=\"\" id=\"search_input\" >"
+ "</span></form></br></br></div></div></div><script type=\"text/javascript\">function search(){if(document.getElementById(\"search_input\").value != \"\"){window.location.href = \"";

private static final String END = "\" + document.getElementById(\"search_input\").value;document.getElementById(\"search_input\").value = \"\";}return false;}</script></body></html>";

@NonNull
public static File getStartPageFile(@NonNull Application application) {
return new File(application.getFilesDir(), FILENAME);
}

@NonNull private final String mTitle;

@Inject Application mApp;
@Inject PreferenceManager mPreferenceManager;
@Inject SearchEngineProvider mSearchEngineProvider;

public StartPage() {
BrowserApp.getAppComponent().inject(this);
@@ -71,87 +77,18 @@ public Single<String> getHomepage() {
public void onSubscribe(@NonNull SingleSubscriber<String> subscriber) {

StringBuilder homepageBuilder = new StringBuilder(HEAD_1 + mTitle + HEAD_2);
String icon;
String searchUrl;
switch (mPreferenceManager.getSearchChoice()) {
case 0:
// CUSTOM SEARCH
icon = "file:///android_asset/lightning.png";
searchUrl = mPreferenceManager.getSearchUrl();
break;
case 1:
// GOOGLE_SEARCH;
icon = "file:///android_asset/google.png";
// "https://www.google.com/images/srpr/logo11w.png";
searchUrl = Constants.GOOGLE_SEARCH;
break;
case 2:
// ANDROID SEARCH;
icon = "file:///android_asset/ask.png";
searchUrl = Constants.ASK_SEARCH;
break;
case 3:
// BING_SEARCH;
icon = "file:///android_asset/bing.png";
// "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Bing_logo_%282013%29.svg/500px-Bing_logo_%282013%29.svg.png";
searchUrl = Constants.BING_SEARCH;
break;
case 4:
// YAHOO_SEARCH;
icon = "file:///android_asset/yahoo.png";
// "http://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Yahoo%21_logo.svg/799px-Yahoo%21_logo.svg.png";
searchUrl = Constants.YAHOO_SEARCH;
break;
case 5:
// STARTPAGE_SEARCH;
icon = "file:///android_asset/startpage.png";
// "https://com/graphics/startp_logo.gif";
searchUrl = Constants.STARTPAGE_SEARCH;
break;
case 6:
// STARTPAGE_MOBILE
icon = "file:///android_asset/startpage.png";
// "https://com/graphics/startp_logo.gif";
searchUrl = Constants.STARTPAGE_MOBILE_SEARCH;
break;
case 7:
// DUCK_SEARCH;
icon = "file:///android_asset/duckduckgo.png";
// "https://duckduckgo.com/assets/logo_homepage.normal.v101.png";
searchUrl = Constants.DUCK_SEARCH;
break;
case 8:
// DUCK_LITE_SEARCH;
icon = "file:///android_asset/duckduckgo.png";
// "https://duckduckgo.com/assets/logo_homepage.normal.v101.png";
searchUrl = Constants.DUCK_LITE_SEARCH;
break;
case 9:
// BAIDU_SEARCH;
icon = "file:///android_asset/baidu.png";
// "http://www.baidu.com/img/bdlogo.gif";
searchUrl = Constants.BAIDU_SEARCH;
break;
case 10:
// YANDEX_SEARCH;
icon = "file:///android_asset/yandex.png";
// "http://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Yandex.svg/600px-Yandex.svg.png";
searchUrl = Constants.YANDEX_SEARCH;
break;
default:
// DEFAULT GOOGLE_SEARCH;
icon = "file:///android_asset/google.png";
searchUrl = Constants.GOOGLE_SEARCH;
break;

}
BaseSearchEngine currentSearchEngine = mSearchEngineProvider.getCurrentSearchEngine();

String icon = currentSearchEngine.getIconUrl();
String searchUrl = currentSearchEngine.getQueryUrl();

homepageBuilder.append(icon);
homepageBuilder.append(MIDDLE);
homepageBuilder.append(searchUrl);
homepageBuilder.append(END);

File homepage = new File(mApp.getFilesDir(), FILENAME);
File homepage = getStartPageFile(mApp);
FileWriter hWriter = null;
try {
//noinspection IOResourceOpenedButNotSafelyClosed
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient.CustomViewCallback;

import acr.browser.lightning.activity.TabsManager;
import acr.browser.lightning.browser.TabsManager;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.view.LightningView;
@@ -28,7 +28,7 @@ public interface UIController {

boolean getUseDarkTheme();

void updateUrl(@Nullable String title, boolean shortUrl);
void updateUrl(@Nullable String title, boolean isLoading);

void updateProgress(int n);

44 changes: 20 additions & 24 deletions app/src/main/java/acr/browser/lightning/database/HistoryItem.java
Original file line number Diff line number Diff line change
@@ -11,21 +11,15 @@

public class HistoryItem implements Comparable<HistoryItem> {

// private variables
@NonNull
private String mUrl = "";

@NonNull
private String mTitle = "";

@NonNull
private String mFolder = "";

@Nullable
private Bitmap mBitmap = null;
@NonNull private String mUrl = "";
@NonNull private String mTitle = "";
@NonNull private String mFolder = "";
@Nullable private Bitmap mBitmap = null;

private int mImageId = 0;

private int mPosition = 0;

private boolean mIsFolder = false;

public HistoryItem() {}
@@ -115,35 +109,37 @@ public String toString() {

@Override
public int compareTo(@NonNull HistoryItem another) {
int compare = this.mTitle.compareTo(another.mTitle);
int compare = this.mTitle.compareToIgnoreCase(another.mTitle);
if (compare == 0) {
return this.mUrl.compareTo(another.mUrl);
}
return compare;
}

@Override
public boolean equals(@Nullable Object object) {

if (this == object) return true;
if (object == null) return false;
if (!(object instanceof HistoryItem)) return false;
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

HistoryItem that = (HistoryItem) object;
HistoryItem that = (HistoryItem) o;

return mImageId == that.mImageId &&
this.mTitle.equals(that.mTitle) && this.mUrl.equals(that.mUrl) &&
this.mFolder.equals(that.mFolder);
mPosition == that.mPosition &&
mIsFolder == that.mIsFolder &&
mUrl.equals(that.mUrl) &&
mTitle.equals(that.mTitle) &&
mFolder.equals(that.mFolder);

}

@Override
public int hashCode() {

int result = mUrl.hashCode();
result = 31 * result + mImageId;
result = 31 * result + mTitle.hashCode();
result = 32 * result + mFolder.hashCode();
result = 31 * result + mFolder.hashCode();
result = 31 * result + mImageId;
result = 31 * result + mPosition;
result = 31 * result + (mIsFolder ? 1 : 0);

return result;
}
Original file line number Diff line number Diff line change
@@ -75,7 +75,7 @@ public BookmarkDatabase(@NonNull Application application) {
*/
@WorkerThread
@NonNull
private SQLiteDatabase lazyDatabase() {
private synchronized SQLiteDatabase lazyDatabase() {
if (mDatabase == null || !mDatabase.isOpen()) {
mDatabase = getWritableDatabase();
}
@@ -105,6 +105,13 @@ public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion
onCreate(db);
}

/**
* Binds a {@link HistoryItem} to {@link ContentValues}.
*
* @param bookmarkItem the bookmark to bind.
* @return a valid values object that can be inserted
* into the database.
*/
@NonNull
private static ContentValues bindBookmarkToContentValues(@NonNull HistoryItem bookmarkItem) {
ContentValues contentValues = new ContentValues(4);
@@ -116,6 +123,15 @@ private static ContentValues bindBookmarkToContentValues(@NonNull HistoryItem bo
return contentValues;
}

/**
* Binds a cursor to a {@link HistoryItem}. This is
* a non consuming operation on the cursor. Note that
* this operation is not safe to perform on a cursor
* unless you know that the cursor is of history items.
*
* @param cursor the cursor to read from.
* @return a valid item containing all the pertinent information.
*/
@NonNull
private static HistoryItem bindCursorToHistoryItem(@NonNull Cursor cursor) {
HistoryItem bookmark = new HistoryItem();
@@ -129,6 +145,13 @@ private static HistoryItem bindCursorToHistoryItem(@NonNull Cursor cursor) {
return bookmark;
}

/**
* Binds a cursor to a list of {@link HistoryItem}.
* This operation consumes the cursor.
*
* @param cursor the cursor to bind.
* @return a valid list of history items, may be empty.
*/
@NonNull
private static List<HistoryItem> bindCursorToHistoryItemList(@NonNull Cursor cursor) {
List<HistoryItem> bookmarks = new ArrayList<>();
@@ -142,13 +165,91 @@ private static List<HistoryItem> bindCursorToHistoryItemList(@NonNull Cursor cur
return bookmarks;
}

/**
* URLs can represent the same thing with or without a trailing slash,
* for instance, google.com/ is the same page as google.com. Since these
* can be represented as different bookmarks within the bookmark database,
* it is important to be able to get the alternate version of a URL.
*
* @param url the string that might have a trailing slash.
* @return a string without a trailing slash if the original had one,
* or a string with a trailing slash if the original did not.
*/
@NonNull
private static String alternateSlashUrl(@NonNull String url) {
if (url.endsWith("/")) {
return url.substring(0, url.length() - 1);
} else {
return url + '/';
}
}

/**
* Queries the database for bookmarks with the provided URL. If it
* cannot find any bookmarks with the given URL, it will try to query
* for bookmarks with the {@link #alternateSlashUrl(String)} as its URL.
*
* @param url the URL to query for.
* @return a cursor with bookmarks matching the URL.
*/
@NonNull
private Cursor queryWithOptionalEndSlash(@NonNull String url) {
Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{url}, null, null, null, "1");

if (cursor.getCount() == 0) {
String alternateUrl = alternateSlashUrl(url);
cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{alternateUrl}, null, null, null, "1");
}

return cursor;
}

/**
* Deletes a bookmark from the database with the provided URL. If it
* cannot find any bookmark with the given URL, it will try to delete
* a bookmark with the {@link #alternateSlashUrl(String)} as its URL.
*
* @param url the URL to delete.
* @return the number of deleted rows.
*/
private int deleteWithOptionalEndSlash(@NonNull String url) {
int deletedRows = lazyDatabase().delete(TABLE_BOOKMARK, KEY_URL + "=?", new String[]{url});

if (deletedRows == 0) {
String alternateUrl = alternateSlashUrl(url);
deletedRows = lazyDatabase().delete(TABLE_BOOKMARK, KEY_URL + "=?", new String[]{alternateUrl});
}

return deletedRows;
}

/**
* Updates a bookmark in the database with the provided URL. If it
* cannot find any bookmark with the given URL, it will try to update
* a bookmark with the {@link #alternateSlashUrl(String)} as its URL.
*
* @param url the URL to update.
* @param contentValues the new values to update to.
* @return the numebr of rows updated.
*/
private int updateWithOptionalEndSlash(@NonNull String url, @NonNull ContentValues contentValues) {
int updatedRows = lazyDatabase().update(TABLE_BOOKMARK, contentValues, KEY_URL + "=?", new String[]{url});

if (updatedRows == 0) {
String alternateUrl = alternateSlashUrl(url);
updatedRows = lazyDatabase().update(TABLE_BOOKMARK, contentValues, KEY_URL + "=?", new String[]{alternateUrl});
}

return updatedRows;
}

@NonNull
@Override
public Single<HistoryItem> findBookmarkForUrl(@NonNull final String url) {
return Single.create(new SingleAction<HistoryItem>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<HistoryItem> subscriber) {
Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{url}, null, null, null, "1");
Cursor cursor = queryWithOptionalEndSlash(url);

if (cursor.moveToFirst()) {
subscriber.onItem(bindCursorToHistoryItem(cursor));
@@ -168,7 +269,7 @@ public Single<Boolean> isBookmark(@NonNull final String url) {
return Single.create(new SingleAction<Boolean>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<Boolean> subscriber) {
Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{url}, null, null, null, "1");
Cursor cursor = queryWithOptionalEndSlash(url);

subscriber.onItem(cursor.moveToFirst());

@@ -184,7 +285,7 @@ public Single<Boolean> addBookmarkIfNotExists(@NonNull final HistoryItem item) {
return Single.create(new SingleAction<Boolean>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<Boolean> subscriber) {
Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{item.getUrl()}, null, null, null, "1");
Cursor cursor = queryWithOptionalEndSlash(item.getUrl());

if (cursor.moveToFirst()) {
cursor.close();
@@ -229,7 +330,7 @@ public Single<Boolean> deleteBookmark(@NonNull final HistoryItem bookmark) {
return Single.create(new SingleAction<Boolean>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<Boolean> subscriber) {
int rows = lazyDatabase().delete(TABLE_BOOKMARK, KEY_URL + "=?", new String[]{bookmark.getUrl()});
int rows = deleteWithOptionalEndSlash(bookmark.getUrl());

subscriber.onItem(rows > 0);
subscriber.onComplete();
@@ -290,7 +391,7 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
}
ContentValues contentValues = bindBookmarkToContentValues(newBookmark);

lazyDatabase().update(TABLE_BOOKMARK, contentValues, KEY_URL + "=?", new String[]{oldBookmark.getUrl()});
updateWithOptionalEndSlash(oldBookmark.getUrl(), contentValues);

subscriber.onComplete();
}
Original file line number Diff line number Diff line change
@@ -10,15 +10,9 @@

public class DownloadItem implements Comparable<DownloadItem> {

// private variables
@NonNull
private String mUrl = "";

@NonNull
private String mTitle = "";

@NonNull
private String mContentSize = "";
@NonNull private String mUrl = "";
@NonNull private String mTitle = "";
@NonNull private String mContentSize = "";

public DownloadItem() {}

@@ -66,31 +60,31 @@ public String toString() {

@Override
public int compareTo(@NonNull DownloadItem another) {
int compare = this.mTitle.compareTo(another.mTitle);
int compare = this.mTitle.compareToIgnoreCase(another.mTitle);
if (compare == 0) {
return this.mUrl.compareTo(another.mUrl);
}
return compare;
}

@Override
public boolean equals(@Nullable Object object) {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

if (this == object) return true;
if (object == null) return false;
if (!(object instanceof DownloadItem)) return false;
DownloadItem that = (DownloadItem) o;

DownloadItem that = (DownloadItem) object;
return mUrl.equals(that.mUrl) &&
mTitle.equals(that.mTitle) &&
mContentSize.equals(that.mContentSize);

return this.mTitle.equals(that.mTitle) && this.mUrl.equals(that.mUrl)
&& this.mContentSize.equals(that.mContentSize);
}

@Override
public int hashCode() {

int result = mUrl.hashCode();
result = 31 * result + mTitle.hashCode();
result = 31 * result + mContentSize.hashCode();

return result;
}
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ public DownloadsDatabase(@NonNull Application application) {
*/
@WorkerThread
@NonNull
private SQLiteDatabase lazyDatabase() {
private synchronized SQLiteDatabase lazyDatabase() {
if (mDatabase == null || !mDatabase.isOpen()) {
mDatabase = getWritableDatabase();
}
Original file line number Diff line number Diff line change
@@ -13,6 +13,13 @@
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;

import com.anthonycr.bonsai.Completable;
import com.anthonycr.bonsai.CompletableAction;
import com.anthonycr.bonsai.CompletableSubscriber;
import com.anthonycr.bonsai.Single;
import com.anthonycr.bonsai.SingleAction;
import com.anthonycr.bonsai.SingleSubscriber;

import java.util.ArrayList;
import java.util.List;

@@ -22,9 +29,15 @@
import acr.browser.lightning.R;
import acr.browser.lightning.database.HistoryItem;


/**
* The disk backed download database.
* See {@link HistoryModel} for method
* documentation.
*/
@Singleton
@WorkerThread
public class HistoryDatabase extends SQLiteOpenHelper {
public class HistoryDatabase extends SQLiteOpenHelper implements HistoryModel {

// All Static variables
// Database Version
@@ -45,9 +58,8 @@ public class HistoryDatabase extends SQLiteOpenHelper {
@Nullable private SQLiteDatabase mDatabase;

@Inject
HistoryDatabase(@NonNull Application application) {
public HistoryDatabase(@NonNull Application application) {
super(application, DATABASE_NAME, null, DATABASE_VERSION);
mDatabase = HistoryDatabase.this.getWritableDatabase();
}

// Creating Tables
@@ -80,40 +92,108 @@ private static HistoryItem fromCursor(@NonNull Cursor cursor) {

@WorkerThread
@NonNull
private SQLiteDatabase lazyDatabase() {
private synchronized SQLiteDatabase lazyDatabase() {
if (mDatabase == null || !mDatabase.isOpen()) {
mDatabase = this.getWritableDatabase();
}
return mDatabase;
}

@WorkerThread
synchronized void deleteHistory() {
lazyDatabase().delete(TABLE_HISTORY, null, null);
lazyDatabase().close();
@NonNull
@Override
public Completable deleteHistory() {
return Completable.create(new CompletableAction() {
@Override
public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
lazyDatabase().delete(TABLE_HISTORY, null, null);
lazyDatabase().close();

subscriber.onComplete();
}
});
}

@WorkerThread
synchronized void deleteHistoryItem(@NonNull String url) {
lazyDatabase().delete(TABLE_HISTORY, KEY_URL + " = ?", new String[]{url});
@NonNull
@Override
public Completable deleteHistoryItem(@NonNull final String url) {
return Completable.create(new CompletableAction() {
@Override
public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
lazyDatabase().delete(TABLE_HISTORY, KEY_URL + " = ?", new String[]{url});

subscriber.onComplete();
}
});
}

@WorkerThread
synchronized void visitHistoryItem(@NonNull String url, @Nullable String title) {
ContentValues values = new ContentValues();
values.put(KEY_TITLE, title == null ? "" : title);
values.put(KEY_TIME_VISITED, System.currentTimeMillis());
@NonNull
@Override
public Completable visitHistoryItem(@NonNull final String url, @Nullable final String title) {
return Completable.create(new CompletableAction() {
@Override
public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
ContentValues values = new ContentValues();
values.put(KEY_TITLE, title == null ? "" : title);
values.put(KEY_TIME_VISITED, System.currentTimeMillis());

Cursor cursor = lazyDatabase().query(false, TABLE_HISTORY, new String[]{KEY_URL},
KEY_URL + " = ?", new String[]{url}, null, null, null, "1");

if (cursor.getCount() > 0) {
lazyDatabase().update(TABLE_HISTORY, values, KEY_URL + " = ?", new String[]{url});
} else {
addHistoryItem(new HistoryItem(url, title == null ? "" : title));
}

cursor.close();
}
});
}

Cursor cursor = lazyDatabase().query(false, TABLE_HISTORY, new String[]{KEY_URL},
KEY_URL + " = ?", new String[]{url}, null, null, null, "1");
@NonNull
@Override
public Single<List<HistoryItem>> findHistoryItemsContaining(@NonNull final String query) {
return Single.create(new SingleAction<List<HistoryItem>>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<List<HistoryItem>> subscriber) {
List<HistoryItem> itemList = new ArrayList<>(5);

if (cursor.getCount() > 0) {
lazyDatabase().update(TABLE_HISTORY, values, KEY_URL + " = ?", new String[]{url});
} else {
addHistoryItem(new HistoryItem(url, title == null ? "" : title));
}
String search = '%' + query + '%';

cursor.close();
Cursor cursor = lazyDatabase().query(TABLE_HISTORY, null, KEY_TITLE + " LIKE ? OR " + KEY_URL + " LIKE ?",
new String[]{search, search}, null, null, KEY_TIME_VISITED + " DESC", "5");

while (cursor.moveToNext()) {
itemList.add(fromCursor(cursor));
}

cursor.close();

subscriber.onItem(itemList);
subscriber.onComplete();
}
});
}

@NonNull
@Override
public Single<List<HistoryItem>> lastHundredVisitedHistoryItems() {
return Single.create(new SingleAction<List<HistoryItem>>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<List<HistoryItem>> subscriber) {
List<HistoryItem> itemList = new ArrayList<>(100);
Cursor cursor = lazyDatabase().query(TABLE_HISTORY, null, null, null, null, null, KEY_TIME_VISITED + " DESC", "100");

while (cursor.moveToNext()) {
itemList.add(fromCursor(cursor));
}

cursor.close();

subscriber.onItem(itemList);
subscriber.onComplete();
}
});
}

@WorkerThread
@@ -140,43 +220,6 @@ synchronized String getHistoryItem(@NonNull String url) {
return m;
}

@WorkerThread
@NonNull
synchronized List<HistoryItem> findItemsContaining(@Nullable String search) {
List<HistoryItem> itemList = new ArrayList<>(5);
if (search == null) {
return itemList;
}

search = '%' + search + '%';

Cursor cursor = lazyDatabase().query(TABLE_HISTORY, null, KEY_TITLE + " LIKE ? OR " + KEY_URL + " LIKE ?",
new String[]{search, search}, null, null, KEY_TIME_VISITED + " DESC", "5");

while (cursor.moveToNext()) {
itemList.add(fromCursor(cursor));
}

cursor.close();

return itemList;
}

@WorkerThread
@NonNull
synchronized List<HistoryItem> getLastHundredItems() {
List<HistoryItem> itemList = new ArrayList<>(100);
Cursor cursor = lazyDatabase().query(TABLE_HISTORY, null, null, null, null, null, KEY_TIME_VISITED + " DESC", "100");

while (cursor.moveToNext()) {
itemList.add(fromCursor(cursor));
}

cursor.close();

return itemList;
}

@WorkerThread
@NonNull
synchronized List<HistoryItem> getAllHistoryItems() {
Original file line number Diff line number Diff line change
@@ -4,43 +4,27 @@
import android.support.annotation.Nullable;

import com.anthonycr.bonsai.Completable;
import com.anthonycr.bonsai.CompletableAction;
import com.anthonycr.bonsai.CompletableSubscriber;
import com.anthonycr.bonsai.Single;
import com.anthonycr.bonsai.SingleAction;
import com.anthonycr.bonsai.SingleSubscriber;

import java.util.List;

import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.database.HistoryItem;

/**
* A model class providing reactive bindings
* with the underlying history database.
* An interface that should be used to communicate
* with the history database.
* <p>
* Created by anthonycr on 6/9/17.
*/
public final class HistoryModel {

private HistoryModel() {}
public interface HistoryModel {

/**
* An observable that deletes browser history.
*
* @return a valid observable.
*/
@NonNull
public static Completable deleteHistory() {
return Completable.create(new CompletableAction() {
@Override
public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
BrowserApp.getAppComponent()
.historyDatabase()
.deleteHistory();

subscriber.onComplete();
}
});
}
Completable deleteHistory();

/**
* An observable that deletes the history
@@ -50,18 +34,7 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
* @return a valid observable.
*/
@NonNull
public static Completable deleteHistoryItem(@NonNull final String url) {
return Completable.create(new CompletableAction() {
@Override
public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
BrowserApp.getAppComponent()
.historyDatabase()
.deleteHistoryItem(url);

subscriber.onComplete();
}
});
}
Completable deleteHistoryItem(@NonNull final String url);

/**
* An observable that visits the URL by
@@ -74,18 +47,7 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
* @return a valid observable.
*/
@NonNull
public static Completable visitHistoryItem(@NonNull final String url, @Nullable final String title) {
return Completable.create(new CompletableAction() {
@Override
public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
BrowserApp.getAppComponent()
.historyDatabase()
.visitHistoryItem(url, title);

subscriber.onComplete();
}
});
}
Completable visitHistoryItem(@NonNull final String url, @Nullable final String title);

/**
* An observable that finds all history items
@@ -100,18 +62,7 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) {
* a list of history items.
*/
@NonNull
public static Single<List<HistoryItem>> findHistoryItemsContaining(@NonNull final String query) {
return Single.create(new SingleAction<List<HistoryItem>>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<List<HistoryItem>> subscriber) {
List<HistoryItem> result = BrowserApp.getAppComponent()
.historyDatabase().findItemsContaining(query);

subscriber.onItem(result);
subscriber.onComplete();
}
});
}
Single<List<HistoryItem>> findHistoryItemsContaining(@NonNull final String query);

/**
* An observable that emits a list of the
@@ -121,16 +72,5 @@ public void onSubscribe(@NonNull SingleSubscriber<List<HistoryItem>> subscriber)
* a list of history items.
*/
@NonNull
public static Single<List<HistoryItem>> lastHundredVisitedHistoryItems() {
return Single.create(new SingleAction<List<HistoryItem>>() {
@Override
public void onSubscribe(@NonNull SingleSubscriber<List<HistoryItem>> subscriber) {
List<HistoryItem> result = BrowserApp.getAppComponent()
.historyDatabase().getLastHundredItems();

subscriber.onItem(result);
subscriber.onComplete();
}
});
}
Single<List<HistoryItem>> lastHundredVisitedHistoryItems();
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
package acr.browser.lightning.app;
package acr.browser.lightning.di;

import javax.inject.Singleton;

import acr.browser.lightning.activity.BrowserActivity;
import acr.browser.lightning.activity.ReadingActivity;
import acr.browser.lightning.activity.TabsManager;
import acr.browser.lightning.activity.ThemableBrowserActivity;
import acr.browser.lightning.activity.ThemableSettingsActivity;
import acr.browser.lightning.browser.activity.BrowserActivity;
import acr.browser.lightning.reading.activity.ReadingActivity;
import acr.browser.lightning.browser.TabsManager;
import acr.browser.lightning.browser.activity.ThemableBrowserActivity;
import acr.browser.lightning.settings.activity.ThemableSettingsActivity;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.browser.BrowserPresenter;
import acr.browser.lightning.browser.SearchBoxModel;
import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.DownloadsPage;
import acr.browser.lightning.constant.HistoryPage;
import acr.browser.lightning.constant.StartPage;
import acr.browser.lightning.database.history.HistoryDatabase;
import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.download.DownloadHandler;
import acr.browser.lightning.download.LightningDownloadListener;
import acr.browser.lightning.fragment.BookmarkSettingsFragment;
import acr.browser.lightning.fragment.BookmarksFragment;
import acr.browser.lightning.fragment.DebugSettingsFragment;
import acr.browser.lightning.fragment.LightningPreferenceFragment;
import acr.browser.lightning.fragment.PrivacySettingsFragment;
import acr.browser.lightning.fragment.TabsFragment;
import acr.browser.lightning.settings.fragment.BookmarkSettingsFragment;
import acr.browser.lightning.browser.fragment.BookmarksFragment;
import acr.browser.lightning.settings.fragment.DebugSettingsFragment;
import acr.browser.lightning.settings.fragment.GeneralSettingsFragment;
import acr.browser.lightning.settings.fragment.LightningPreferenceFragment;
import acr.browser.lightning.settings.fragment.PrivacySettingsFragment;
import acr.browser.lightning.browser.fragment.TabsFragment;
import acr.browser.lightning.search.SearchEngineProvider;
import acr.browser.lightning.search.SuggestionsAdapter;
import acr.browser.lightning.utils.ProxyUtils;
import acr.browser.lightning.view.LightningChromeClient;
@@ -80,6 +84,12 @@ public interface AppComponent {

void inject(LightningChromeClient chromeClient);

HistoryDatabase historyDatabase();
void inject(DownloadHandler downloadHandler);

void inject(SearchBoxModel searchBoxModel);

void inject(SearchEngineProvider searchEngineProvider);

void inject(GeneralSettingsFragment generalSettingsFragment);

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package acr.browser.lightning.app;
package acr.browser.lightning.di;

import android.app.Application;
import android.content.Context;
@@ -8,10 +8,14 @@

import javax.inject.Singleton;

import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.database.bookmark.BookmarkDatabase;
import acr.browser.lightning.database.bookmark.BookmarkModel;
import acr.browser.lightning.database.downloads.DownloadsDatabase;
import acr.browser.lightning.database.downloads.DownloadsModel;
import acr.browser.lightning.database.history.HistoryDatabase;
import acr.browser.lightning.database.history.HistoryModel;
import acr.browser.lightning.download.DownloadHandler;
import dagger.Module;
import dagger.Provides;

@@ -36,17 +40,31 @@ public Context provideContext() {
@NonNull
@Provides
@Singleton
public BookmarkModel provideBookmarkMode() {
public BookmarkModel provideBookmarkModel() {
return new BookmarkDatabase(mApp);
}

@NonNull
@Provides
@Singleton
public DownloadsModel provideDownloadsMode() {
public DownloadsModel provideDownloadsModel() {
return new DownloadsDatabase(mApp);
}

@NonNull
@Provides
@Singleton
public HistoryModel providesHistoryModel() {
return new HistoryDatabase(mApp);
}

@NonNull
@Provides
@Singleton
public DownloadHandler provideDownloadHandler() {
return new DownloadHandler();
}

@NonNull
@Provides
@Singleton
Original file line number Diff line number Diff line change
@@ -82,8 +82,8 @@ public static void show(@NonNull Activity activity, @Nullable String title, @Non

View layout = LayoutInflater.from(activity).inflate(R.layout.list_dialog, null);

TextView titleView = (TextView) layout.findViewById(R.id.dialog_title);
ListView listView = (ListView) layout.findViewById(R.id.dialog_list);
TextView titleView = layout.findViewById(R.id.dialog_title);
ListView listView = layout.findViewById(R.id.dialog_list);

ArrayAdapter<String> adapter = new ArrayAdapter<>(activity,
android.R.layout.simple_list_item_1);
@@ -136,7 +136,7 @@ public static void showEditText(@NonNull Activity activity,
@StringRes int action,
@NonNull final EditorListener listener) {
View dialogView = LayoutInflater.from(activity).inflate(R.layout.dialog_edit_text, null);
final EditText editText = (EditText) dialogView.findViewById(R.id.dialog_edit_text);
final EditText editText = dialogView.findViewById(R.id.dialog_edit_text);

editText.setHint(hint);
if (currentText != null) {
Original file line number Diff line number Diff line change
@@ -8,9 +8,7 @@
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.webkit.URLUtil;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
@@ -24,20 +22,20 @@
import javax.inject.Inject;

import acr.browser.lightning.R;
import acr.browser.lightning.activity.MainActivity;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.MainActivity;
import acr.browser.lightning.BrowserApp;
import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.controller.UIController;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.database.bookmark.BookmarkModel;
import acr.browser.lightning.database.downloads.DownloadItem;
import acr.browser.lightning.database.downloads.DownloadsModel;
import acr.browser.lightning.database.history.HistoryModel;
import acr.browser.lightning.download.DownloadHandler;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.IntentUtils;
import acr.browser.lightning.utils.Preconditions;
import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.utils.UrlUtils;

/**
* TODO Rename this class it doesn't build dialogs only for bookmarks
@@ -55,7 +53,9 @@ public enum NewTab {

@Inject BookmarkModel mBookmarkManager;
@Inject DownloadsModel mDownloadsModel;
@Inject HistoryModel mHistoryModel;
@Inject PreferenceManager mPreferenceManager;
@Inject DownloadHandler mDownloadHandler;

@Inject
public LightningDialogBuilder() {
@@ -73,7 +73,7 @@ public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity
@NonNull final UIController uiController,
@NonNull final String url) {
final HistoryItem item;
if (url.startsWith(Constants.FILE) && url.endsWith(BookmarkPage.FILENAME)) {
if (UrlUtils.isBookmarkUrl(url)) {
// TODO hacky, make a better bookmark mechanism in the future
final Uri uri = Uri.parse(url);
final String filename = uri.getLastPathSegment();
@@ -91,6 +91,7 @@ public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity
.subscribe(new SingleOnSubscribe<HistoryItem>() {
@Override
public void onItem(@Nullable HistoryItem historyItem) {
// TODO: 6/14/17 figure out solution to case where slashes get appended to root urls causing the item to be null
if (historyItem != null) {
showLongPressedDialogForBookmarkUrl(activity, uiController, historyItem);
}
@@ -191,12 +192,12 @@ private void showEditBookmarkDialog(@NonNull final Activity activity,
final AlertDialog.Builder editBookmarkDialog = new AlertDialog.Builder(activity);
editBookmarkDialog.setTitle(R.string.title_edit_bookmark);
final View dialogLayout = View.inflate(activity, R.layout.dialog_edit_bookmark, null);
final EditText getTitle = (EditText) dialogLayout.findViewById(R.id.bookmark_title);
final EditText getTitle = dialogLayout.findViewById(R.id.bookmark_title);
getTitle.setText(item.getTitle());
final EditText getUrl = (EditText) dialogLayout.findViewById(R.id.bookmark_url);
final EditText getUrl = dialogLayout.findViewById(R.id.bookmark_url);
getUrl.setText(item.getUrl());
final AutoCompleteTextView getFolder =
(AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder);
dialogLayout.findViewById(R.id.bookmark_folder);
getFolder.setHint(R.string.folder);
getFolder.setText(item.getFolder());

@@ -332,7 +333,7 @@ public void onClick() {
new BrowserDialog.Item(R.string.dialog_remove_from_history) {
@Override
public void onClick() {
HistoryModel.deleteHistoryItem(url)
mHistoryModel.deleteHistoryItem(url)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.main())
.subscribe(new CompletableOnSubscribe() {
@@ -384,16 +385,7 @@ public void onClick() {
new BrowserDialog.Item(R.string.dialog_download_image) {
@Override
public void onClick() {
Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment");

mDownloadsModel.addDownloadIfNotExists(new DownloadItem(url, URLUtil.guessFileName(url, null, null), ""))
.subscribe(new SingleOnSubscribe<Boolean>() {
@Override
public void onItem(@Nullable Boolean item) {
if (item != null && !item)
Log.i(TAG, "error saving download to database");
}
});
mDownloadHandler.onDownloadStart(activity, mPreferenceManager, url, userAgent, "attachment", null, "");
}
});
}
Loading

0 comments on commit e00bb88

Please sign in to comment.