Commit 28e682a8 authored by beriain's avatar beriain
Browse files

Upload project

parents
# 1.0
- Initial release
\ No newline at end of file
This diff is collapsed.
# <img src="https://framagit.org/uploads/-/system/project/avatar/32207/ic_launcher.png?width=22" alt="" height="40"> Search searx
An unofficial Searx app.
With a homescreen widget and an easy way to select instances.
This app can be built using [Debian Android SDK](https://bits.debian.org/2017/03/build-android-apps-with-debian.html)
\ No newline at end of file
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "search.searx"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
archivesBaseName = "search-searx"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\Android garapena\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="search.searx">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<activity
android:name="search.searx.MainActivity"
android:theme="@style/MainTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="search.searx.AboutActivity"
android:theme="@style/AboutTheme" />
<receiver android:name="SearchWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/search_widget_info" />
</receiver>
</application>
</manifest>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width = device-width, initial-scale = 1, maximum-scale = 1, minimum-scale = 1">
<script type="text/javascript">
var instanceInfo = [];
var translations = ["This", "Select", "Instance", "Grade", "Version", "Time", "Custom instance:", "Set"];
function translate() {
if (navigator.language.startsWith("es")) {
translations = ["Esta", "Seleccionar", "Instancia", "Nota", "Versión", "Tiempo", "Instancia personalizada:", "Establecer"];
} else if (navigator.language.startsWith("eu")) {
translations = ["Hau", "Hautatu", "Instantzia", "Nota", "Bertsioa", "Denbora", "Instantzia pertsonalizatua:", "Ezarri"];
}
document.getElementById("select").textContent = translations[1];
document.getElementById("instance").textContent = translations[2];
document.getElementById("grade").textContent = translations[3];
document.getElementById("version").textContent = translations[4];
document.getElementById("time").textContent = translations[5];
document.getElementById("advanced").textContent = translations[6];
document.getElementById("setCustomInstance").textContent = translations[7];
}
function setInstance(element) {
var instance = element.target.getAttribute("instance");
Android.setInstance(instance);
}
function setCustomInstance() {
var instance = document.getElementById("customInstance").value;
if (!instance.endsWith("/")) {
instance += "/";
}
Android.setInstance(instance);
}
function refreshTable() {
var table = document.getElementById("instancesTable");
var tbody = table.children[1];
tbody.innerHTML = "";
for (var x = 0; x < instanceInfo.length; x++) {
var row = tbody.insertRow(-1);
var t = row.insertCell(0);
var select = document.createElement("button");
select.textContent = translations[0];
select.setAttribute("instance", instanceInfo[x].url);
select.onclick = setInstance;
t.appendChild(select);
var u = row.insertCell(1);
u.innerHTML = instanceInfo[x].url;
var g = row.insertCell(2);
g.innerHTML = instanceInfo[x].grade;
var v = row.insertCell(3);
v.innerHTML = instanceInfo[x].version;
var t = row.insertCell(4);
t.innerHTML = instanceInfo[x].time;
}
scroll(document.body.scrollLeft, 0);
}
function downloadAndParse() {
var xhr= new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
var searx = JSON.parse(this.responseText);
//convert Object to Array
var instances = Object.entries(searx.instances);
console.log(instances);
for (var x = 0; x < instances.length; x++) {
if (instances[x][1].http.status_code != null &&
instances[x][1].http.grade != null &&
instances[x][1].timing.search.all != null &&
instances[x][1].timing.search.all.median != null) {
instanceInfo.push({url:instances[x][0],
grade:instances[x][1].http.grade,
version:instances[x][1].version,
time:instances[x][1].timing.search.all.median});
}
}
refreshTable();
console.log(instanceInfo);
}
}
xhr.open("GET", "https://searx.space/data/instances.json", true);
xhr.send();
}
/****/
downloadAndParse();
/****/
function sortByUrl() {
instanceInfo = instanceInfo.sort(function (a, b) {
return ("" + a.url).localeCompare(b.url);
});
refreshTable();
}
function sortByGrade() {
instanceInfo = instanceInfo.sort(function (a, b) {
return ("" + a.grade).localeCompare(b.grade, "en");
});
refreshTable();
}
function sortByVersion() {
instanceInfo = instanceInfo.sort(function (a, b) {
return ("" + b.version).localeCompare(a.version);
});
refreshTable();
}
function sortByTime() {
instanceInfo = instanceInfo.sort(function (a, b) {
return a.time - b.time;
});
refreshTable();
}
</script>
<style>
body {
margin: 0;
font-family: sans-serif;
}
table {
border-collapse: collapse;
}
th {
position: sticky;
top: 0;
background: #3faa7e;
color: #fff;
}
td {
border: 1px solid black;
}
button {
width: 100%;
}
button#setCustomInstance {
width: auto;
}
</style>
</head>
<body onload="translate()">
<table id="instancesTable">
<thead>
<tr>
<th id="select">Select</th>
<th id="instance" onclick="sortByUrl()">Instance</th>
<th id="grade" onclick="sortByGrade()">Grade</th>
<th id="version" onclick="sortByVersion()">Version</th>
<th id="time" onclick="sortByTime()">Time</th>
</tr>
</thead>
<tbody></tbody>
</table>
<span id="advanced">Custom instance:</span>
<input type="text" id="customInstance" value="https://"/>
<button id="setCustomInstance" onclick="setCustomInstance()">Set</button>
</body>
</html>
\ No newline at end of file
package search.searx;
import android.app.Activity;
import android.os.Bundle;
import android.os.Build;
import android.view.WindowManager;
import android.widget.TextView;
import search.searx.BuildConfig;
public class AboutActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
}
setContentView(R.layout.activity_about);
TextView version = (TextView) findViewById(R.id.version);
version.setText(BuildConfig.VERSION_NAME);
}
}
package search.searx;
import android.app.Activity;
import android.os.Bundle;
import android.os.Build;
import android.view.WindowManager;
import android.webkit.WebView;
import android.content.SharedPreferences;
import android.widget.EditText;
import android.widget.TextView;
import android.view.inputmethod.EditorInfo;
import android.view.KeyEvent;
import android.view.View;
import android.content.Intent;
import android.view.inputmethod.InputMethodManager;
import android.app.AlertDialog;
import android.text.method.LinkMovementMethod;
import android.content.DialogInterface;
import android.preference.PreferenceManager;
import android.webkit.WebViewClient;
import android.view.LayoutInflater;
import android.net.Uri;
import android.webkit.URLUtil;
import android.widget.Toast;
import android.webkit.JavascriptInterface;
public class MainActivity extends Activity {
public String instance = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
}
setContentView(R.layout.activity_main);
//Check if an instance has been set
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
instance = preferences.getString("pref_instance", "");
//if there is no instance selected open list to select one
if (instance.compareTo("") == 0) {
WebView wv = (WebView) findViewById(R.id.viewer);
wv.requestFocus();
selectInstance(new View(MainActivity.this));
}
EditText et = (EditText) findViewById(R.id.searchfield);
et.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
search(view.getText().toString());
view.setText("");
View v = MainActivity.this.getCurrentFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(MainActivity.this.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
return true;
}
return false;
}
});
WebView wv = (WebView) findViewById(R.id.viewer);
wv.getSettings().setJavaScriptEnabled(true);
wv.addJavascriptInterface(new jsinterface(), "Android");
wv.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//let opening the preferences inside the app
if (url.startsWith(instance))
return false;
else { //otherwise launch a web browser
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
return true;
}
}
});
}
public void search(String searchTerm) {
if (instance.compareTo("") == 0) {
selectInstance(new View(MainActivity.this));
} else {
WebView wv = (WebView) findViewById(R.id.viewer);
wv.getSettings().setJavaScriptEnabled(true);
wv.loadUrl(instance + "?q=" + searchTerm);
/*POST - not working
wv.postUrl(instance, Base64.encode(searchTerm.getBytes(), Base64.DEFAULT));*/
}
}
public void selectInstance(View view) {
WebView wv = (WebView) findViewById(R.id.viewer);
wv.getSettings().setJavaScriptEnabled(true);
wv.loadUrl("file:///android_asset/instanceParser.html");
//hide keyboard
View v = MainActivity.this.getCurrentFocus();
if (v != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(MainActivity.this.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
public class jsinterface {
@JavascriptInterface
public void setInstance(String i) {
instance = i;
PreferenceManager.getDefaultSharedPreferences(MainActivity.this).edit().putString("pref_instance", instance).commit();
Toast.makeText(MainActivity.this, instance + " " + getResources().getString(R.string.selected), Toast.LENGTH_SHORT).show();
final WebView wv = (WebView) findViewById(R.id.viewer);
wv.post(new Runnable() {
@Override
public void run() {
wv.getSettings().setJavaScriptEnabled(true);
wv.loadUrl(instance);
}
});
}
}
public void displayAbout(View view) {
Intent i = new Intent(MainActivity.this, AboutActivity.class);
MainActivity.this.startActivity(i);
}
}
package search.searx;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.appwidget.AppWidgetManager;
import android.widget.RemoteViews;
import android.content.Intent;
import android.app.PendingIntent;
public class SearchWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.search_appwidget);
Intent configIntent = new Intent(context, MainActivity.class);
PendingIntent configPendingIntent = PendingIntent.getActivity(context, 0, configIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.searchwidget, configPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment