From 60e0a9dd9336b5209eaa59285413592babd4f210 Mon Sep 17 00:00:00 2001 From: Schoumi Date: Wed, 20 May 2015 16:10:30 +0200 Subject: [PATCH] First Commit of the project before cleanup and gpl header add --- .gitignore | 15 +- app/.gitignore | 1 + app/build.gradle | 25 ++ .../fr/mobdev/gobelim/ApplicationTest.java | 13 + app/src/main/AndroidManifest.xml | 42 +++ .../main/java/fr/mobdev/gobelim/Database.java | 162 +++++++++ .../fr/mobdev/gobelim/NetworkManager.java | 215 +++++++++++ .../gobelim/activity/HistoryActivity.java | 120 +++++++ .../mobdev/gobelim/activity/LinkActivity.java | 60 ++++ .../mobdev/gobelim/activity/MainActivity.java | 340 ++++++++++++++++++ .../gobelim/activity/ServersActivity.java | 175 +++++++++ .../mobdev/gobelim/dialog/ServerDialog.java | 67 ++++ .../gobelim/listener/NetworkListener.java | 11 + .../gobelim/listener/ServerListener.java | 7 + .../java/fr/mobdev/gobelim/objects/Img.java | 77 ++++ .../fr/mobdev/gobelim/objects/Server.java | 31 ++ app/src/main/res/layout/history.xml | 13 + app/src/main/res/layout/history_item.xml | 40 +++ app/src/main/res/layout/link.xml | 45 +++ app/src/main/res/layout/main.xml | 67 ++++ app/src/main/res/layout/server_dialog.xml | 21 ++ app/src/main/res/layout/server_item.xml | 20 ++ app/src/main/res/layout/servers.xml | 15 + app/src/main/res/menu/menu_main.xml | 14 + app/src/main/res/menu/menu_servers.xml | 8 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes app/src/main/res/values-w820dp/dimens.xml | 6 + app/src/main/res/values/dimens.xml | 5 + app/src/main/res/values/strings.xml | 36 ++ app/src/main/res/values/styles.xml | 8 + build.gradle | 19 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes gradle/wrapper/gradle-wrapper.properties | 6 + settings.gradle | 1 + 37 files changed, 1675 insertions(+), 10 deletions(-) create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/src/androidTest/java/fr/mobdev/gobelim/ApplicationTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/fr/mobdev/gobelim/Database.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/NetworkManager.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/activity/HistoryActivity.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/activity/LinkActivity.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/activity/MainActivity.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/activity/ServersActivity.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/dialog/ServerDialog.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/listener/NetworkListener.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/listener/ServerListener.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/objects/Img.java create mode 100644 app/src/main/java/fr/mobdev/gobelim/objects/Server.java create mode 100644 app/src/main/res/layout/history.xml create mode 100644 app/src/main/res/layout/history_item.xml create mode 100644 app/src/main/res/layout/link.xml create mode 100644 app/src/main/res/layout/main.xml create mode 100644 app/src/main/res/layout/server_dialog.xml create mode 100644 app/src/main/res/layout/server_item.xml create mode 100644 app/src/main/res/layout/servers.xml create mode 100644 app/src/main/res/menu/menu_main.xml create mode 100644 app/src/main/res/menu/menu_servers.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index ccf2efe..d92797a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,3 @@ -# Built application files -*.apk -*.ap_ - -# Files for the Dalvik VM -*.dex - -# Java class files -*.class - # Generated files bin/ gen/ @@ -16,6 +6,7 @@ gen/ .gradle/ build/ /*/build/ +gradlew* # Local configuration file (sdk path, etc) local.properties @@ -25,3 +16,7 @@ proguard/ # Log Files *.log + +#android-studio file +.idea +*.iml diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..046b503 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "21.1.2" + + defaultConfig { + applicationId "fr.mobdev.gobelim" + minSdkVersion 11 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.0.0' +} diff --git a/app/src/androidTest/java/fr/mobdev/gobelim/ApplicationTest.java b/app/src/androidTest/java/fr/mobdev/gobelim/ApplicationTest.java new file mode 100644 index 0000000..ab27f17 --- /dev/null +++ b/app/src/androidTest/java/fr/mobdev/gobelim/ApplicationTest.java @@ -0,0 +1,13 @@ +package fr.mobdev.gobelim; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8bb39a2 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/fr/mobdev/gobelim/Database.java b/app/src/main/java/fr/mobdev/gobelim/Database.java new file mode 100644 index 0000000..f40a00e --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/Database.java @@ -0,0 +1,162 @@ +package fr.mobdev.gobelim; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.TimeZone; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.database.sqlite.SQLiteOpenHelper; + +import fr.mobdev.gobelim.objects.Img; +import fr.mobdev.gobelim.objects.Server; + +public class Database extends SQLiteOpenHelper { + + private static Database instance; + + public static Database getInstance(Context context) + { + if(instance == null) + instance = new Database(context, "Lutim.db", null, 1); + return instance; + } + + private Database(Context context, String name, CursorFactory factory, int version) { + super(context, name, factory, version); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("Create table if not exists history (" + + "id integer primary key autoincrement, url varchar(1024), short_hash varchar(1024), real_short_hash varchar(1024), date INTEGER, storage_duration INTEGER ,thumb TEXT);"); + db.execSQL("Create table if not exists servers (" + + "id integer primary key autoincrement, url varchar(1024), isDefault INTEGER);"); + + ContentValues values = new ContentValues(); + values.put("url","https://framapic.org"); + values.put("isDefault",true); + db.insert("servers",null,values); + values.clear(); + values.put("url","https://lut.im"); + values.put("isDefault",false); + db.insert("servers", null, values); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + //nothing to do right now + } + + public List getHistory() { + List history = new ArrayList(); + String orderBy = "date ASC"; + Cursor cursor = getReadableDatabase().query("history", null, null, null, null, null, orderBy); + while(cursor.moveToNext()) + { + int col = 0; + long id = cursor.getLong(col++); + String url = cursor.getString(col++); + String shortHash = cursor.getString(col++); + String realShortHash = cursor.getString(col++); + long timestamp = cursor.getLong(col++); + int storageDuration = cursor.getInt(col++); + byte[] thumbData = cursor.getBlob(col++); + + Calendar date = Calendar.getInstance(); + date.setTimeZone(TimeZone.getTimeZone("Europe/Paris")); + date.setTimeInMillis(timestamp); + + Img img = new Img(id, url, shortHash, realShortHash, date, storageDuration, thumbData); + + history.add(img); + } + return history; + } + + public void deleteImg(List deletedList) { + for(Img img : deletedList) + { + String whereClause = "id = ?"; + String[] whereArgs = new String[1]; + whereArgs[0] = String.valueOf(img.getId()); + getWritableDatabase().delete("history", whereClause, whereArgs); + } + } + + public void addImage(Img img) { + ContentValues values = new ContentValues(); + values.put("url", img.getUrl()); + values.put("short_hash", img.getShortHash()); + values.put("real_short_hash", img.getRealShortHash()); + values.put("date", img.getDate().getTimeInMillis()); + values.put("storage_duration", img.getStorageDuration()); + if(img.getThumbData() != null) + values.put("thumb",img.getThumbData()); + getWritableDatabase().insert("history", null, values); + } + + public void addServer(String url) + { + ContentValues values = new ContentValues(); + values.put("url",url); + values.put("isDefault",false); + getWritableDatabase().insert("servers", null, values); + } + + public List getServers(boolean defaultFirst) + { + List servers = new ArrayList(); + Cursor cursor = getReadableDatabase().query("servers", null, null, null, null, null, null); + while(cursor.moveToNext()) + { + int col = 0; + long id = cursor.getLong(col++); + String url = cursor.getString(col++); + int defValue = cursor.getInt(col++); + boolean isDefault = false; + if(defValue == 1) + isDefault = true; + Server server = new Server(id, url, isDefault); + if(defaultFirst && isDefault) + { + servers.add(0,server); + } + else + { + servers.add(server); + } + + } + return servers; + } + + public void deleteServer(long idServer) + { + String whereClause ="id = ?"; + String[] whereArgs = new String[1]; + whereArgs[0] = String.valueOf(idServer); + getWritableDatabase().delete("servers",whereClause,whereArgs); + } + + public void setDefaultServer(long newDefaultId, long oldDefaultId) + { + String whereClause = "id = ?"; + String[] whereargs = new String[1]; + whereargs[0] = String.valueOf(newDefaultId); + ContentValues values = new ContentValues(); + values.put("isDefault",true); + getWritableDatabase().update("servers", values, whereClause, whereargs); + + if(oldDefaultId != -1) { + values.clear(); + whereargs[0] = String.valueOf(oldDefaultId); + values.put("isDefault", false); + getWritableDatabase().update("servers", values, whereClause, whereargs); + } + } +} diff --git a/app/src/main/java/fr/mobdev/gobelim/NetworkManager.java b/app/src/main/java/fr/mobdev/gobelim/NetworkManager.java new file mode 100644 index 0000000..1bb966c --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/NetworkManager.java @@ -0,0 +1,215 @@ +package fr.mobdev.gobelim; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Calendar; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.NetworkInfo.State; +import android.util.Log; + +import fr.mobdev.gobelim.listener.NetworkListener; +import fr.mobdev.gobelim.objects.Img; + +public class NetworkManager { + + private NetworkListener listener; + private static NetworkManager instance; + private Context context; + private static int id; + + private NetworkManager(NetworkListener listener,Context context) + { + this.listener = listener; + this.context = context; + } + + public static NetworkManager getInstance(NetworkListener listener, Context context){ + if (instance == null) + instance = new NetworkManager(listener,context); + if(listener != instance.getListener()) + instance.setListener(listener); + return instance; + } + + private NetworkListener getListener() + { + return listener; + } + + private void setListener(NetworkListener listener) + { + this.listener = listener; + } + + public void upload(final String siteUrl, final int nbDays, final String fileName, final byte[] bytearray) + { + if(!isConnectedToInternet(context)) + return; + new Thread(new Runnable() { + + @Override + public void run() { + Img img = uploadImage(siteUrl,nbDays, fileName,bytearray); + if(img != null) + listener.fileUploaded(img); + } + }).start(); + } + + public Img uploadImage(String siteUrl, int nbDays, String fileName, byte[] byteArray) { + Log.v("Url",siteUrl); + //getData + URL url = null; + Img imgOutput = null; + try { + url = new URL(siteUrl); + } catch (MalformedURLException e1) { + e1.printStackTrace(); + } + + HttpURLConnection conn = null; + InputStream stream = null; + DataOutputStream request = null; + try { + if(isConnectedToInternet(context)) + { + String attachmentFileName = fileName; + String crlf = "\r\n"; + String hyphens = "--"; + String boundary = "------------------------dd8a045fcc22b35c"; + + conn = (HttpURLConnection) url.openConnection(); + + int responseCode = conn.getResponseCode(); + + String location = conn.getHeaderField("Location"); + if(location != null) { + siteUrl = location; + url = new URL(location); + } + conn = (HttpURLConnection) url.openConnection(); + + conn.setRequestMethod("POST"); + conn.setUseCaches(false); + conn.setDoInput(true); + conn.setDoOutput(true); + + conn.setRequestProperty("User-Agent", "Gobelim"); +// conn.setFixedLengthStreamingMode(byteArray.length); +// conn.setChunkedStreamingMode(0); + + conn.setInstanceFollowRedirects(true); + //conn.set + conn.setRequestProperty("Expect", "100-continue"); + conn.setRequestProperty("Accept", "*/*"); + conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + + + request = new DataOutputStream(conn.getOutputStream()); + + request.writeBytes(hyphens + boundary + crlf); + request.writeBytes("Content-Disposition: form-data; name=\"format\"" + crlf); + request.writeBytes(crlf); + request.writeBytes("json" + crlf); + + request.writeBytes(hyphens + boundary + crlf); + request.writeBytes("Content-Disposition: form-data; name=\"delete-day\"" + crlf); + request.writeBytes(crlf); + request.writeBytes(nbDays + crlf); + + request.writeBytes(hyphens + boundary + crlf); + request.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + attachmentFileName + "\"" + crlf); + request.writeBytes("Content-Type: application/octet-stream" + crlf); + request.writeBytes(crlf); + request.flush(); + + request.write(byteArray); + + request.writeBytes(crlf); + request.writeBytes(hyphens + boundary + hyphens + crlf); + request.flush(); + + stream = conn.getInputStream(); + } + } catch (IOException e1) { + e1.printStackTrace(); + listener.fileUploadError("Network Error"); + } + + /******************************************************************************/ + if(stream != null) { + InputStreamReader isr = new InputStreamReader(stream); + BufferedReader br = new BufferedReader(isr); + boolean isReading = true; + String data; + String jsonStr = ""; + do { + try { + data = br.readLine(); + if (data != null) + jsonStr += data; + else + isReading = false; + } catch (IOException e) { + e.printStackTrace(); + isReading = false; + } + } while (isReading); + //parseJSon + try { + request.close(); + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + System.out.println("after read answer"); + System.out.println(jsonStr); + try { + JSONObject rootObject = new JSONObject(jsonStr); // Parse the JSON to a JSONObject + JSONObject msg = rootObject.getJSONObject("msg"); // Get the element object + if(msg.has("msg")) { + String error = msg.getString("msg"); + listener.fileUploadError(error); + return null; + } + else if(msg.has("short")) { + String hashOutput = msg.getString("short"); + String realHashOutput = msg.getString("real_short"); + imgOutput = new Img(0, siteUrl, hashOutput, realHashOutput, Calendar.getInstance(), nbDays, null); + } + } catch (JSONException e) { + // JSON Parsing error + e.printStackTrace(); + listener.fileUploadError("JSON Unreadable"); + } + } + return imgOutput; + } + + private boolean isConnectedToInternet(Context context) + { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); + if (networkInfo != null) + { + State networkState = networkInfo.getState(); + if (networkState.equals(State.CONNECTED)) + { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/mobdev/gobelim/activity/HistoryActivity.java b/app/src/main/java/fr/mobdev/gobelim/activity/HistoryActivity.java new file mode 100644 index 0000000..105e166 --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/activity/HistoryActivity.java @@ -0,0 +1,120 @@ +package fr.mobdev.gobelim.activity; + +import android.content.Context; +import android.content.Intent; +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + +import fr.mobdev.gobelim.Database; +import fr.mobdev.gobelim.objects.Img; +import fr.mobdev.gobelim.R; + + +public class HistoryActivity extends ActionBarActivity { + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.history); + ListView historyList = (ListView) findViewById(R.id.history_list); + final List images = Database.getInstance(getApplicationContext()).getHistory(); + HistoryAdapter adapter = new HistoryAdapter(this,R.layout.history_item,R.id.url_history_item,images); + historyList.setAdapter(adapter); + historyList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Intent linkIntent = new Intent(HistoryActivity.this,LinkActivity.class); + if(position < images.size()) { + Img image = images.get(position); + linkIntent.putExtra("URL", image.getUrl()); + linkIntent.putExtra("short", image.getShortHash()); + startActivity(linkIntent); + } + } + }); + } + + private class HistoryAdapter extends ArrayAdapter + { + + private List images; + private LayoutInflater mInflater; + int resource; + + public HistoryAdapter(Context context, int resource, int textViewResourceId, List objects) { + super(context, resource, textViewResourceId, objects); + images = new ArrayList(objects); + this.resource = resource; + mInflater = LayoutInflater.from(context); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) + { + Img image = images.get(position); + if (convertView == null) { + convertView = mInflater.inflate(resource, parent, false); + } + + TextView urlView = (TextView) convertView.findViewById(R.id.url_history_item); + String url = image.getUrl(); + if(!url.endsWith("/")) + url+="/"; + url+=image.getShortHash(); + urlView.setText(url); + + //display date + TextView dateView = (TextView) convertView.findViewById(R.id.date); + Calendar date = image.getDate(); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); + df.setTimeZone(TimeZone.getDefault()); + String dateString = df.format(date.getTime()); + dateView.setText(dateString); + + //display durationLastDay + TextView durationView = (TextView) convertView.findViewById(R.id.duration); + int storageDuration = image.getStorageDuration(); + if(storageDuration == 0) { + durationView.setText(getString(R.string.no_duration)); + } + else { + Calendar today = Calendar.getInstance(); + long millis = today.getTimeInMillis() - date.getTimeInMillis(); + long days = millis / (24*60*60*1000); + if(storageDuration - days < 0) { + durationView.setText(getString(R.string.duration_ended)); + } + else { + if(storageDuration - days == 1) + durationView.setText(storageDuration - days +" "+ getString(R.string.day)); + else + durationView.setText(storageDuration - days +" "+ getString(R.string.days)); + } + } + + + ImageView thumb = (ImageView) convertView.findViewById(R.id.thumbnail); + if(image.getThumb() != null) + thumb.setImageBitmap(image.getThumb()); + + return convertView; + } + } +} + diff --git a/app/src/main/java/fr/mobdev/gobelim/activity/LinkActivity.java b/app/src/main/java/fr/mobdev/gobelim/activity/LinkActivity.java new file mode 100644 index 0000000..48a7e4f --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/activity/LinkActivity.java @@ -0,0 +1,60 @@ +package fr.mobdev.gobelim.activity; + +import android.content.Intent; +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageButton; +import android.widget.TextView; + +import android.content.ClipboardManager; +import android.widget.Toast; + +import fr.mobdev.gobelim.R; + + +public class LinkActivity extends ActionBarActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.link); + + Intent receiveIntent = getIntent(); + String url = receiveIntent.getStringExtra("URL"); + String shortHash = receiveIntent.getStringExtra("short"); + + if(!url.endsWith("/")) + url = url.concat("/"); + url = url.concat(shortHash); + + final String sharedUrl = url; + + ImageButton shareButton = (ImageButton) findViewById(R.id.share_button); + shareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, sharedUrl); + sendIntent.setType("text/plain"); + startActivity(sendIntent); + } + }); + + ImageButton copyClipboardButton = (ImageButton) findViewById(R.id.copy_clipboard_button); + copyClipboardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("Copied URL", sharedUrl); + clipboard.setPrimaryClip(clip); + Toast.makeText(LinkActivity.this,getString(R.string.copy_to_clipboard),Toast.LENGTH_SHORT).show(); + } + }); + + TextView link = (TextView) findViewById(R.id.link); + link.setText(sharedUrl); + } + +} diff --git a/app/src/main/java/fr/mobdev/gobelim/activity/MainActivity.java b/app/src/main/java/fr/mobdev/gobelim/activity/MainActivity.java new file mode 100644 index 0000000..c827a6c --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/activity/MainActivity.java @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2015 Anthony Chomienne, anthony@mob-dev.fr + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package fr.mobdev.gobelim.activity; + +import android.app.ProgressDialog; +import android.content.ContentResolver; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.provider.MediaStore; +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.Spinner; +import android.widget.Toast; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import fr.mobdev.gobelim.Database; +import fr.mobdev.gobelim.listener.NetworkListener; +import fr.mobdev.gobelim.NetworkManager; +import fr.mobdev.gobelim.objects.Img; +import fr.mobdev.gobelim.objects.Server; +import fr.mobdev.gobelim.R; + +public class MainActivity extends ActionBarActivity { + + private NetworkListener listener; + private Uri imageUri; + private String fileName; + private List urls; + private List deletedDays; + private ProgressDialog progressDialog; + + private static final int NEVER = 0; + private static final int ONE = 1; + private static final int SEVEN = 7; + private static final int THIRTY = 30; + private static final int YEAR = 365; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + imageUri = null; + urls = new ArrayList<>(); + deletedDays = new ArrayList<>(); + deletedDays.add(NEVER); + deletedDays.add(ONE); + deletedDays.add(SEVEN); + deletedDays.add(THIRTY); + deletedDays.add(YEAR); + + updateServerList(); + if(savedInstanceState != null) { + int selectedServer = savedInstanceState.getInt("selectedServer"); + imageUri = savedInstanceState.getParcelable("imageURI"); + if (selectedServer < urls.size()) { + Spinner servers = (Spinner) findViewById(R.id.servers_spinner); + servers.setSelection(selectedServer); + } + } + + listener = new NetworkListener() { + @Override + public void fileUploaded(final Img image) { + runOnUiThread(new Runnable() { + @Override + public void run() { + //add uploaded img to history + Database.getInstance(getApplicationContext()).addImage(image); + //dismiss progressDialog + progressDialog.dismiss(); + //launch LinkActivity + Intent linkIntent = new Intent(MainActivity.this,LinkActivity.class); + linkIntent.putExtra("URL", image.getUrl()); + linkIntent.putExtra("short",image.getShortHash()); + startActivity(linkIntent); + } + }); + } + + @Override + public void fileUploadError(final String error) { + runOnUiThread(new Runnable() { + @Override + public void run() { + //display toast error + Toast.makeText(MainActivity.this, error, Toast.LENGTH_SHORT).show(); + progressDialog.dismiss(); + } + }); + } + }; + + Button uploadBt = (Button) findViewById(R.id.upload_button); + uploadBt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + uploadImage(); + } + }); + + //prepare for asking user the image he want share + Button selectBt = (Button) findViewById(R.id.select_button); + selectBt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + requestFile(); + } + }); + + //have we receive image from share or do you need to ask it to the user + Intent receiveIntent = getIntent(); + if(receiveIntent == null || receiveIntent.getType() == null || !receiveIntent.getType().contains("image/")) { + uploadBt.setVisibility(View.GONE); + } + else { + selectBt.setVisibility(View.GONE); + imageUri = receiveIntent.getParcelableExtra(Intent.EXTRA_STREAM); + displayImage(); + } + } + + @Override + protected void onResume() { + super.onResume(); + //update server list to manage change in ServerActivity + updateServerList(); + } + + @Override + protected void onSaveInstanceState(Bundle savedInstanceState) { + savedInstanceState.putParcelable("imageURI", imageUri); + Spinner selectedServer = (Spinner) findViewById(R.id.servers_spinner); + int pos = selectedServer.getSelectedItemPosition(); + savedInstanceState.putInt("selectedServer", pos); + super.onSaveInstanceState(savedInstanceState); + } + + private void updateServerList() { + Spinner serversSpinner = (Spinner) findViewById(R.id.servers_spinner); + String selectedServer = (String) serversSpinner.getSelectedItem(); + + List servers = Database.getInstance(getApplicationContext()).getServers(true); + urls.clear(); + int pos = 0; + for(Server server : servers) { + if(server.getUrl().equals(selectedServer)) { + pos = urls.size(); + } + urls.add(server.getUrl()); + } + + ArrayAdapter adapter = new ArrayAdapter<>(this,android.R.layout.simple_dropdown_item_1line,urls); + serversSpinner.setAdapter(adapter); + + serversSpinner.setSelection(pos); + } + + private void displayImage() { + FileInputStream fileStream = null; + File file; + if(imageUri != null) { + ContentResolver contentResolver = getContentResolver(); + Cursor cursor = contentResolver.query(imageUri, null, null, null, null); + cursor.moveToFirst(); + String filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)); + cursor.close(); + file = new File(filePath); + fileName = file.getName(); + try { + fileStream = new FileInputStream(file); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + if(fileStream != null) { + try { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + int readed = 0; + byte[] buffer = new byte[1024]; + while(readed != -1) { + try { + readed = fileStream.read(buffer); + if(readed != -1) + outStream.write(buffer,0,readed); + } catch (IOException e) { + e.printStackTrace(); + readed = -1; + } + } + byte[] bytearray = outStream.toByteArray(); + + + Bitmap bt = BitmapFactory.decodeByteArray(bytearray,0,bytearray.length); + ImageView view = (ImageView) findViewById(R.id.thumbnail_main); + view.setImageBitmap(bt); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + } + + private void uploadImage() { + //what server we use + Spinner urlSpinner = (Spinner)findViewById(R.id.servers_spinner); + int pos = urlSpinner.getSelectedItemPosition(); + if(urls.size() < pos) { + Toast.makeText(this,getString(R.string.server_list_error),Toast.LENGTH_LONG).show(); + return; + } + String url = urls.get(pos); + + Spinner deleteSpinner = (Spinner)findViewById(R.id.delete_day_spinner); + pos = deleteSpinner.getSelectedItemPosition(); + int delete = deletedDays.get(pos); + + byte[] bytearray = null; + FileInputStream fileStream = null; + if(imageUri != null) { + ContentResolver contentResolver = getContentResolver(); + Cursor cursor = contentResolver.query(imageUri, null, null, null, null); + cursor.moveToFirst(); + String filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)); + cursor.close(); + File file = new File(filePath); + fileName = file.getName(); + try { + fileStream = new FileInputStream(file); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + if(fileStream != null) { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + int readed = 0; + byte[] buffer = new byte[1024]; + while(readed != -1) { + try { + readed = fileStream.read(buffer); + if(readed != -1) + outStream.write(buffer,0,readed); + } catch (IOException e) { + e.printStackTrace(); + readed = -1; + } + } + bytearray = outStream.toByteArray(); + } + if(bytearray != null && bytearray.length > 0) { + progressDialog = new ProgressDialog(MainActivity.this); + progressDialog.setMessage(getString(R.string.upload_progress)); + progressDialog.setCancelable(false); + progressDialog.show(); + NetworkManager.getInstance(listener, getApplicationContext()).upload(url, delete, fileName, bytearray); + } + else { + listener.fileUploadError("Empty file or Unable to read the file"); + } + } + + protected void requestFile() { + Intent requestFileIntent = new Intent(Intent.ACTION_PICK); + requestFileIntent.setType("image/*"); + startActivityForResult(requestFileIntent, 0); + } + + @Override + public void onActivityResult(int requestCode, int resultCode,Intent returnIntent) { + if(resultCode == RESULT_OK){ + imageUri = returnIntent.getData(); + Button uploadBt = (Button) findViewById(R.id.upload_button); + uploadBt.setVisibility(View.VISIBLE); + + Button selectButton = (Button) findViewById(R.id.select_button); + selectButton.setVisibility(View.GONE); + displayImage(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id == R.id.action_manage_server) { + Intent serverIntent = new Intent(this,ServersActivity.class); + startActivity(serverIntent); + return true; + } + else if (id == R.id.action_show_history){ + Intent historyIntent = new Intent(this,HistoryActivity.class); + startActivity(historyIntent); + return true; + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/fr/mobdev/gobelim/activity/ServersActivity.java b/app/src/main/java/fr/mobdev/gobelim/activity/ServersActivity.java new file mode 100644 index 0000000..0b8972a --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/activity/ServersActivity.java @@ -0,0 +1,175 @@ +package fr.mobdev.gobelim.activity; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Typeface; +import android.provider.ContactsContract; +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import fr.mobdev.gobelim.Database; +import fr.mobdev.gobelim.dialog.ServerDialog; +import fr.mobdev.gobelim.listener.ServerListener; +import fr.mobdev.gobelim.objects.Server; +import fr.mobdev.gobelim.R; + + +public class ServersActivity extends ActionBarActivity { + + private List dbServers; + private View.OnClickListener listener; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.servers); + ListView serverList = (ListView) findViewById(R.id.servers_list); + serverList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + //find oldDefault + Server oldDefaultServer = null; + for(Server server : dbServers) + { + if(server.isDefaultServer()) + { + oldDefaultServer = server; + break; + } + } + Server newDefaultServer = dbServers.get(position); + if(oldDefaultServer == null) { + Database.getInstance(getApplicationContext()).setDefaultServer(newDefaultServer.getId(),-1); + } + else { + Database.getInstance(getApplicationContext()).setDefaultServer(newDefaultServer.getId(), oldDefaultServer.getId()); + } + updateServers(); + return true; + } + }); + + listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + ListView serverList = (ListView) findViewById(R.id.servers_list); + Integer pos = (Integer)v.getTag(); + if(pos == null) + return; + final Server server = dbServers.get(pos.intValue()); + //ask delete + AlertDialog.Builder builder = new AlertDialog.Builder(ServersActivity.this); + builder.setMessage(getString(R.string.delete_server_message)+" "+server.getUrl()) + .setCancelable(false) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dbServers.remove(server); + Database.getInstance(getApplicationContext()).deleteServer(server.getId()); + updateServers(); + } + }) + .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + }; + updateServers(); + } + + private void updateServers() + { + dbServers = Database.getInstance(getApplicationContext()).getServers(false); + + ServerAdapter adapter = new ServerAdapter(this,R.layout.server_item,R.id.server_name,dbServers,listener); + + ListView serverList = (ListView) findViewById(R.id.servers_list); + serverList.setAdapter(adapter); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_servers, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id == R.id.action_add_server) { + + ServerDialog serverDialog = new ServerDialog(); + ServerListener serverListener = new ServerListener() { + @Override + public void updateServerList() { + updateServers(); + } + }; + serverDialog.setServerListener(serverListener); + serverDialog.show(getSupportFragmentManager(),"Server Dialog"); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private class ServerAdapter extends ArrayAdapter + { + + private List servers; + private LayoutInflater mInflater; + private View.OnClickListener listener; + int resource; + + public ServerAdapter(Context context, int resource, int textViewResourceId, List objects, View.OnClickListener listener) { + super(context, resource, textViewResourceId, objects); + servers = new ArrayList(objects); + this.listener = listener; + this.resource = resource; + mInflater = LayoutInflater.from(context); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) + { + Server server = servers.get(position); + if (convertView == null) { + convertView = mInflater.inflate(resource, parent, false); + } + + TextView view = (TextView) convertView.findViewById(R.id.server_name); + if(server.isDefaultServer()) { + Typeface typeface = view.getTypeface(); + Typeface newTypeface = Typeface.create(typeface,Typeface.BOLD); + view.setTypeface(newTypeface); + } + view.setText(server.getUrl()); + + ImageView delete = (ImageView) convertView.findViewById(R.id.server_delete); + delete.setOnClickListener(listener); + delete.setTag(Integer.valueOf(position)); + + return convertView; + } + } +} diff --git a/app/src/main/java/fr/mobdev/gobelim/dialog/ServerDialog.java b/app/src/main/java/fr/mobdev/gobelim/dialog/ServerDialog.java new file mode 100644 index 0000000..b829ac2 --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/dialog/ServerDialog.java @@ -0,0 +1,67 @@ +package fr.mobdev.gobelim.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.Spinner; + +import fr.mobdev.gobelim.Database; +import fr.mobdev.gobelim.listener.ServerListener; +import fr.mobdev.gobelim.R; + + +public class ServerDialog extends DialogFragment { + + private static final int HTTP_POSITION = 0; + private static final int HTTPS_POSITION = 1; + + private ServerListener listener; + + public void setServerListener(ServerListener listener) + { + this.listener = listener; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) + { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + final View view = inflater.inflate(R.layout.server_dialog, null); + + EditText urlText = (EditText) view.findViewById(R.id.url_text); + //mask for url? + + builder.setView(view) + .setTitle(R.string.server_title) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String url = "http"; + Spinner httpSpinner = (Spinner) view.findViewById(R.id.http_spinner); + if(httpSpinner.getSelectedItemPosition() == HTTPS_POSITION) + url += "s"; + url +="://"; + EditText urlText = (EditText) view.findViewById(R.id.url_text); + if(urlText.getText().length() > 0) + url += urlText.getText(); + Database.getInstance(getActivity().getApplicationContext()).addServer(url); + listener.updateServerList(); + dismiss(); + } + }) + .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismiss(); + } + }); + + return builder.create(); + } +} diff --git a/app/src/main/java/fr/mobdev/gobelim/listener/NetworkListener.java b/app/src/main/java/fr/mobdev/gobelim/listener/NetworkListener.java new file mode 100644 index 0000000..9625773 --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/listener/NetworkListener.java @@ -0,0 +1,11 @@ +package fr.mobdev.gobelim.listener; + +import java.util.EventListener; +import java.util.List; + +import fr.mobdev.gobelim.objects.Img; + +public interface NetworkListener extends EventListener{ + void fileUploaded(Img image); + void fileUploadError(String error); +} diff --git a/app/src/main/java/fr/mobdev/gobelim/listener/ServerListener.java b/app/src/main/java/fr/mobdev/gobelim/listener/ServerListener.java new file mode 100644 index 0000000..16a53d3 --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/listener/ServerListener.java @@ -0,0 +1,7 @@ +package fr.mobdev.gobelim.listener; + +import java.util.EventListener; + +public interface ServerListener extends EventListener { + public void updateServerList(); +} diff --git a/app/src/main/java/fr/mobdev/gobelim/objects/Img.java b/app/src/main/java/fr/mobdev/gobelim/objects/Img.java new file mode 100644 index 0000000..c90f182 --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/objects/Img.java @@ -0,0 +1,77 @@ +package fr.mobdev.gobelim.objects; + +import android.graphics.Bitmap; + +import java.io.ByteArrayOutputStream; +import java.util.Calendar; + +public class Img { + + private Long id; + private String url; + private Calendar date; + private int storageDuration; + private Bitmap image; + private String shortHash; + private String realShortHash; + + public Img(long id, String url, String shortHash, String realShortHash, Calendar date, int storageDuration, byte[] thumbData) { + this.url = url; + this.shortHash = shortHash; + this.id = id; + this.realShortHash = realShortHash; + this.date = date; + this.storageDuration = storageDuration; + } + + public Long getId() + { + return id; + } + + public String getUrl() + { + return url; + } + + public Calendar getDate() + { + return date; + } + + public Bitmap getThumb() + { + return image; + } + + public String getShortHash() + { + return shortHash; + } + + public String getRealShortHash() + { + return realShortHash; + } + + public int getStorageDuration() + { + return storageDuration; + } + + public byte[] getThumbData() + { + if(image != null) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.PNG, 100, stream); + byte[] byteArray = stream.toByteArray(); + + return byteArray; + } + else { + return null; + } + } + + +} diff --git a/app/src/main/java/fr/mobdev/gobelim/objects/Server.java b/app/src/main/java/fr/mobdev/gobelim/objects/Server.java new file mode 100644 index 0000000..5871cca --- /dev/null +++ b/app/src/main/java/fr/mobdev/gobelim/objects/Server.java @@ -0,0 +1,31 @@ +package fr.mobdev.gobelim.objects; + +public class Server { + + private long id; + private String url; + private boolean defaultServer; + + public Server(long id, String url, boolean defaultServer) + { + this.id = id; + this.url = url; + this.defaultServer = defaultServer; + } + + public String getUrl() + { + return url; + } + + public long getId() + { + return id; + } + + public boolean isDefaultServer() + { + return defaultServer; + } + +} diff --git a/app/src/main/res/layout/history.xml b/app/src/main/res/layout/history.xml new file mode 100644 index 0000000..ee7ec74 --- /dev/null +++ b/app/src/main/res/layout/history.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/src/main/res/layout/history_item.xml b/app/src/main/res/layout/history_item.xml new file mode 100644 index 0000000..c259d20 --- /dev/null +++ b/app/src/main/res/layout/history_item.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/link.xml b/app/src/main/res/layout/link.xml new file mode 100644 index 0000000..0355f64 --- /dev/null +++ b/app/src/main/res/layout/link.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml new file mode 100644 index 0000000..0104f87 --- /dev/null +++ b/app/src/main/res/layout/main.xml @@ -0,0 +1,67 @@ + + +