Toots saved as drafts

This commit is contained in:
tom79 2017-07-15 14:59:09 +02:00
parent 74c6e46ce3
commit 60b9e574ce
26 changed files with 852 additions and 10 deletions

View File

@ -32,4 +32,5 @@ dependencies {
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
compile 'com.evernote:android-job:1.1.11'
compile 'com.github.chrisbanes:PhotoView:2.0.0'
compile 'com.google.code.gson:gson:2.8.0'
}

View File

@ -43,8 +43,6 @@ import android.widget.Toast;
import android.widget.VideoView;
import com.github.chrisbanes.photoview.OnMatrixChangedListener;
import com.github.chrisbanes.photoview.OnPhotoTapListener;
import com.github.chrisbanes.photoview.OnScaleChangedListener;
import com.github.chrisbanes.photoview.PhotoView;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.FileAsyncHttpResponseHandler;

View File

@ -34,6 +34,7 @@ import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@ -75,12 +76,15 @@ import fr.gouv.etalab.mastodon.client.Entities.Attachment;
import fr.gouv.etalab.mastodon.client.Entities.Error;
import fr.gouv.etalab.mastodon.client.Entities.Mention;
import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.client.Entities.StoredStatus;
import fr.gouv.etalab.mastodon.drawers.AccountsSearchAdapter;
import fr.gouv.etalab.mastodon.drawers.DraftsListAdapter;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAttachmentInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveSearcAccountshInterface;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.StatusStoredDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import mastodon.etalab.gouv.fr.mastodon.R;
@ -117,6 +121,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
private Status tootReply = null;
private String sharedContent, sharedSubject;
private CheckBox toot_sensitive;
public long currentToId;
private String pattern = "^.*(@([a-zA-Z0-9_]{2,}))$";
@Override
@ -133,7 +138,8 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
if( getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//By default the toot is not restored so the id -1 is defined
currentToId = -1;
imageLoader = ImageLoader.getInstance();
options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
.cacheOnDisk(true).resetViewBeforeLoading(true).build();
@ -494,6 +500,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
switch (item.getItemId()) {
case android.R.id.home:
finish();
@ -513,6 +520,143 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
Toast.LENGTH_SHORT).show();
}
return true;
case R.id.action_store:
storeToot();
return true;
case R.id.action_restore:
try{
final List<StoredStatus> drafts = new StatusStoredDAO(TootActivity.this, db).getAllDrafts();
if( drafts == null || drafts.size() == 0){
Toast.makeText(getApplicationContext(), R.string.no_draft, Toast.LENGTH_LONG).show();
return true;
}
AlertDialog.Builder builderSingle = new AlertDialog.Builder(TootActivity.this);
builderSingle.setTitle(getString(R.string.choose_toot));
final DraftsListAdapter draftsListAdapter = new DraftsListAdapter(TootActivity.this, drafts);
final int[] ids = new int[drafts.size()];
int i = 0;
for(StoredStatus draft: drafts){
ids[i] = draft.getId();
i++;
}
builderSingle.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builderSingle.setPositiveButton(R.string.delete_all, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, int which) {
AlertDialog.Builder builder = new AlertDialog.Builder(TootActivity.this);
builder.setTitle(R.string.delete_all);
builder.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogConfirm, int which) {
new StatusStoredDAO(getApplicationContext(), db).removeAllDrafts();
dialogConfirm.dismiss();
dialog.dismiss();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogConfirm, int which) {
dialogConfirm.dismiss();
}
})
.show();
}
});
builderSingle.setAdapter(draftsListAdapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int id = ids[which];
StoredStatus draft = new StatusStoredDAO(TootActivity.this, db).getStatus(id);
Status status = draft.getStatus();
//Retrieves attachments
attachments = status.getMedia_attachments();
toot_picture_container.removeAllViews();
loading_picture.setVisibility(View.GONE);
if( attachments != null && attachments.size() > 0){
toot_picture_container.setVisibility(View.VISIBLE);
int i = 0 ;
for(Attachment attachment: attachments){
String url = attachment.getPreview_url();
if( url == null || url.trim().equals(""))
url = attachment.getUrl();
final ImageView imageView = new ImageView(getApplicationContext());
imageView.setId(Integer.parseInt(attachment.getId()));
imageLoader.displayImage(url, imageView, options);
LinearLayout.LayoutParams imParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
imParams.setMargins(20, 5, 20, 5);
imParams.height = (int) Helper.convertDpToPixel(100, getApplicationContext());
imageView.setAdjustViewBounds(true);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
toot_picture_container.addView(imageView, i, imParams);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showRemove(imageView.getId());
}
});
if( attachments.size() < 4)
toot_picture.setEnabled(true);
toot_sensitive.setVisibility(View.VISIBLE);
i++;
}
}else {
toot_picture_container.setVisibility(View.GONE);
}
//Sensitive content
toot_sensitive.setChecked(status.isSensitive());
if( status.getSpoiler_text() != null && status.getSpoiler_text().length() > 0 ){
toot_cw_content.setText(status.getSpoiler_text());
toot_cw_content.setVisibility(View.VISIBLE);
}else {
toot_cw_content.setText("");
toot_cw_content.setVisibility(View.GONE);
}
String content = status.getContent();
toot_content.setText(content);
toot_content.setSelection(toot_content.getText().length());
switch (status.getVisibility()){
case "public":
visibility = "public";
toot_visibility.setImageResource(R.drawable.ic_action_globe);
break;
case "unlisted":
visibility = "unlisted";
toot_visibility.setImageResource(R.drawable.ic_action_lock_open);
break;
case "private":
visibility = "private";
toot_visibility.setImageResource(R.drawable.ic_action_lock_closed);
break;
case "direct":
visibility = "direct";
toot_visibility.setImageResource(R.drawable.ic_local_post_office);
break;
}
//The current id is set to the draft
currentToId = draft.getId();
dialog.dismiss();
}
});
builderSingle.show();
}catch (Exception e){
Toast.makeText(getApplicationContext(), R.string.toast_error, Toast.LENGTH_LONG).show();
}
return true;
/*case R.id.action_schedule:
if(toot_content.getText().toString().trim().length() == 0 ){
Toast.makeText(getApplicationContext(),R.string.toot_error_no_content, Toast.LENGTH_LONG).show();
return true;
}
return true;*/
default:
return super.onOptionsItemSelected(item);
}
@ -648,6 +792,15 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
dialog.show();
}
@Override
public void onPause(){
super.onPause();
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean storeToot = sharedpreferences.getBoolean(Helper.SET_AUTO_STORE, true);
if( storeToot)
storeToot();
}
@Override
public void onPostAction(int statusCode, API.StatusAction statusAction, String userId, Error error) {
if( error != null){
@ -700,4 +853,38 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
}
}
private void storeToot(){
//Nothing to store here....
if(toot_content.getText().toString().trim().length() == 0 && (attachments == null || attachments.size() <1) && toot_cw_content.getText().toString().trim().length() == 0)
return;
Status toot = new Status();
toot.setSensitive(isSensitive);
toot.setMedia_attachments(attachments);
if( toot_cw_content.getText().toString().trim().length() > 0)
toot.setSpoiler_text(toot_cw_content.getText().toString().trim());
toot.setVisibility(visibility);
toot.setContent(toot_content.getText().toString().trim());
if( tootReply != null)
toot.setIn_reply_to_id(tootReply.getId());
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
try{
if( currentToId == -1 ) {
currentToId = new StatusStoredDAO(TootActivity.this, db).insertStatus(toot, false, null);
}else{
StoredStatus storedStatus = new StatusStoredDAO(TootActivity.this, db).getStatus(currentToId);
if( storedStatus != null ){
new StatusStoredDAO(TootActivity.this, db).updateStatus(currentToId, toot);
}else { //Might have been deleted, so it needs insertion
new StatusStoredDAO(TootActivity.this, db).insertStatus(toot, false, null);
}
}
Toast.makeText(getApplicationContext(), R.string.toast_toot_saved, Toast.LENGTH_LONG).show();
}catch (Exception e){
Toast.makeText(getApplicationContext(), R.string.toast_error, Toast.LENGTH_LONG).show();
}
}
}

View File

@ -0,0 +1,94 @@
package fr.gouv.etalab.mastodon.client.Entities;
import java.util.Date;
/**
* Created by Thomas on 15/07/2017.
* Manage Stored status
*/
public class StoredStatus {
private int id;
private Date creation_date;
private Date scheduled_date;
private Date sent_date;
private boolean isScheduled;
private boolean isSent;
private Status status;
private String instance;
private String acct;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getCreation_date() {
return creation_date;
}
public void setCreation_date(Date creation_date) {
this.creation_date = creation_date;
}
public Date getScheduled_date() {
return scheduled_date;
}
public void setScheduled_date(Date scheduled_date) {
this.scheduled_date = scheduled_date;
}
public Date getSent_date() {
return sent_date;
}
public void setSent_date(Date sent_date) {
this.sent_date = sent_date;
}
public boolean isScheduled() {
return isScheduled;
}
public void setScheduled(boolean scheduled) {
isScheduled = scheduled;
}
public boolean isSent() {
return isSent;
}
public void setSent(boolean sent) {
isSent = sent;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public String getInstance() {
return instance;
}
public void setInstance(String instance) {
this.instance = instance;
}
public String getAcct() {
return acct;
}
public void setAcct(String acct) {
this.acct = acct;
}
}

View File

@ -0,0 +1,142 @@
package fr.gouv.etalab.mastodon.drawers;
/* Copyright 2017 Thomas Schneider
*
* This file is a part of Mastalab
*
* 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.
*
* Mastalab 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 Thomas Schneider; if not,
* see <http://www.gnu.org/licenses>. */
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import fr.gouv.etalab.mastodon.client.Entities.StoredStatus;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import fr.gouv.etalab.mastodon.sqlite.StatusStoredDAO;
import mastodon.etalab.gouv.fr.mastodon.R;
import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
/**
* Created by Thomas on 15/07/2017.
* Adapter for toot drafts
*/
public class DraftsListAdapter extends BaseAdapter {
private List<StoredStatus> storedStatuses;
private LayoutInflater layoutInflater;
private Context context;
private DraftsListAdapter draftsListAdapter;
public DraftsListAdapter(Context context, List<StoredStatus> storedStatuses){
this.storedStatuses = storedStatuses;
this.context = context;
layoutInflater = LayoutInflater.from(context);
draftsListAdapter = this;
}
@Override
public int getCount() {
return storedStatuses.size();
}
@Override
public Object getItem(int position) {
return storedStatuses.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final StoredStatus draft = storedStatuses.get(position);
final ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.drawer_draft, parent, false);
holder = new ViewHolder();
holder.draft_title = (TextView) convertView.findViewById(R.id.draft_title);
holder.draft_date = (TextView) convertView.findViewById(R.id.draft_date);
holder.draft_delete = (ImageView) convertView.findViewById(R.id.draft_delete);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_DARK){
changeDrawableColor(context, R.drawable.ic_cancel,R.color.dark_text);
}else {
changeDrawableColor(context, R.drawable.ic_cancel,R.color.black);
}
final SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
if(draft.getStatus() != null && draft.getStatus().getContent() != null ) {
if (draft.getStatus().getContent().length() > 20)
holder.draft_title.setText(draft.getStatus().getContent().substring(0, 20));
else
holder.draft_title.setText(draft.getStatus().getContent());
}
holder.draft_date.setText(Helper.dateToString(context, draft.getCreation_date()));
holder.draft_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(draft.getStatus().getContent() + '\n' + draft.getCreation_date());
builder.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.remove_draft)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new StatusStoredDAO(context, db).remove(draft.getId());
storedStatuses.remove(draft);
draftsListAdapter.notifyDataSetChanged();
dialog.dismiss();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.show();
}
});
return convertView;
}
private class ViewHolder {
TextView draft_title;
TextView draft_date;
ImageView draft_delete;
}
}

View File

@ -62,6 +62,8 @@ public class SettingsFragment extends Fragment {
boolean show_reply = sharedpreferences.getBoolean(Helper.SET_SHOW_REPLY, false);
boolean auto_store = sharedpreferences.getBoolean(Helper.SET_AUTO_STORE, true);
final CheckBox set_show_reply = (CheckBox) rootView.findViewById(R.id.set_show_reply);
set_show_reply.setChecked(show_reply);
@ -74,6 +76,17 @@ public class SettingsFragment extends Fragment {
}
});
final CheckBox set_auto_store = (CheckBox) rootView.findViewById(R.id.set_auto_store);
set_auto_store.setChecked(auto_store);
set_auto_store.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_AUTO_STORE, set_auto_store.isChecked());
editor.apply();
}
});
boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true);
final CheckBox set_show_error_messages = (CheckBox) rootView.findViewById(R.id.set_show_error_messages);
set_show_error_messages.setChecked(show_error_messages);

View File

@ -67,6 +67,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.gson.Gson;
import com.loopj.android.http.BuildConfig;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
@ -108,6 +109,7 @@ import fr.gouv.etalab.mastodon.activities.WebviewActivity;
import fr.gouv.etalab.mastodon.asynctasks.RemoveAccountAsyncTask;
import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.Entities.Mention;
import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.client.Entities.Tag;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
@ -168,6 +170,7 @@ public class Helper {
public static final String SET_THEME = "set_theme";
public static final String SET_TIME_FROM = "set_time_from";
public static final String SET_TIME_TO = "set_time_to";
public static final String SET_AUTO_STORE = "set_auto_store";
public static final int ATTACHMENT_ALWAYS = 1;
public static final int ATTACHMENT_WIFI = 2;
public static final int ATTACHMENT_ASK = 3;
@ -1218,4 +1221,14 @@ public class Helper {
return true;
}
}
public static String statusToStringStorage(Status status){
Gson gson = new Gson();
return gson.toJson(status);
}
public static Status restoreStatusFromString(String serializedStatus){
Gson gson = new Gson();
return gson.fromJson(serializedStatus, Status.class);
}
}

View File

@ -26,7 +26,7 @@ import android.database.sqlite.SQLiteOpenHelper;
@SuppressWarnings("WeakerAccess")
public class Sqlite extends SQLiteOpenHelper {
public static final int DB_VERSION = 1;
public static final int DB_VERSION = 2;
public static final String DB_NAME = "mastodon_etalab_db";
public static SQLiteDatabase db;
private static Sqlite sInstance;
@ -36,7 +36,8 @@ public class Sqlite extends SQLiteOpenHelper {
*/
//Table of owned accounts
static final String TABLE_USER_ACCOUNT = "USER_ACCOUNT";
//Table of stored status
static final String TABLE_STATUSES_STORED = "STATUSES_STORED";
public static final String COL_USER_ID = "USER_ID";
@ -69,6 +70,21 @@ public class Sqlite extends SQLiteOpenHelper {
+ COL_INSTANCE + " TEXT NOT NULL, " + COL_OAUTHTOKEN + " TEXT NOT NULL, " + COL_CREATED_AT + " TEXT NOT NULL)";
public static final String COL_ID = "ID";
public static final String COL_STATUS_SERIALIZED = "STATUS_SERIALIZED";
public static final String COL_DATE_CREATION = "DATE_CREATION";
public static final String COL_IS_SCHEDULED = "IS_SCHEDULED";
public static final String COL_DATE_SCHEDULED = "DATE_SCHEDULED";
public static final String COL_SENT = "SENT";
public static final String COL_DATE_SENT = "DATE_SENT";
private static final String CREATE_TABLE_STATUSES_STORED = "CREATE TABLE " + TABLE_STATUSES_STORED + " ("
+ COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COL_USER_ID + " TEXT NOT NULL, " + COL_INSTANCE + " TEXT NOT NULL, "
+ COL_STATUS_SERIALIZED + " TEXT NOT NULL, " + COL_DATE_CREATION + " TEXT NOT NULL, "
+ COL_IS_SCHEDULED + " INTEGER NOT NULL, " + COL_DATE_SCHEDULED + " TEXT, "
+ COL_SENT + " INTEGER NOT NULL, " + COL_DATE_SENT + " TEXT)";
public Sqlite(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
@ -86,12 +102,14 @@ public class Sqlite extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_USER_ACCOUNT);
db.execSQL(CREATE_TABLE_STATUSES_STORED);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL(CREATE_TABLE_STATUSES_STORED);
default:
break;
}

View File

@ -0,0 +1,281 @@
package fr.gouv.etalab.mastodon.sqlite;
/* Copyright 2017 Thomas Schneider
*
* This file is a part of Mastalab
*
* 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.
*
* Mastalab 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 Thomas Schneider; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.client.Entities.StoredStatus;
import fr.gouv.etalab.mastodon.helper.Helper;
/**
* Created by Thomas on 15/07/2017.
* Manage Status storage in DB
*/
public class StatusStoredDAO {
private SQLiteDatabase db;
public Context context;
public StatusStoredDAO(Context context, SQLiteDatabase db) {
//Creation of the DB with tables
this.context = context;
this.db = db;
}
//------- INSERTIONS -------
/**
* Insert a status in database
* @param status Status
* @return boolean
*/
public long insertStatus(Status status, boolean isScheduled, Date scheduled_date)
{
ContentValues values = new ContentValues();
String serializedStatus = Helper.statusToStringStorage(status);
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
String instance = Helper.getLiveInstance(context);
if( userId == null || instance == null)
return -1;
values.put(Sqlite.COL_STATUS_SERIALIZED, serializedStatus);
values.put(Sqlite.COL_DATE_CREATION, Helper.dateToString(context, new Date()));
values.put(Sqlite.COL_IS_SCHEDULED, isScheduled?1:0);
values.put(Sqlite.COL_INSTANCE, instance);
values.put(Sqlite.COL_USER_ID, userId);
values.put(Sqlite.COL_SENT, 0);
if( isScheduled && scheduled_date != null)
values.put(Sqlite.COL_DATE_SCHEDULED, Helper.dateToString(context, scheduled_date));
//Inserts stored status
long last_id;
try{
last_id = db.insert(Sqlite.TABLE_STATUSES_STORED, null, values);
}catch (Exception e) {
last_id = -1;
}
return last_id;
}
//------- UPDATES -------
/**
* Update a Status in database
* @param status Status
* @return boolean
*/
public int updateStatus(long id, Status status ) {
ContentValues values = new ContentValues();
String serializedStatus = Helper.statusToStringStorage(status);
values.put(Sqlite.COL_STATUS_SERIALIZED, serializedStatus);
values.put(Sqlite.COL_DATE_CREATION, Helper.dateToString(context, new Date()));
return db.update(Sqlite.TABLE_STATUSES_STORED,
values, Sqlite.COL_ID + " = ? ",
new String[]{String.valueOf(id)});
}
/**
* Update scheduled date for a Status in database
* @param scheduled_date Date
* @return boolean
*/
public int updateScheduledDate(long id, Date scheduled_date) {
ContentValues values = new ContentValues();
values.put(Sqlite.COL_DATE_SCHEDULED, Helper.dateToString(context, scheduled_date));
return db.update(Sqlite.TABLE_STATUSES_STORED,
values, Sqlite.COL_ID + " = ? ",
new String[]{String.valueOf(id)});
}
/**
* Update date when task is done for a scheduled Status in database
* @param date_sent Date
* @return boolean
*/
public int updateScheduledDone(long id, Date date_sent) {
ContentValues values = new ContentValues();
values.put(Sqlite.COL_DATE_SENT, Helper.dateToString(context, date_sent));
values.put(Sqlite.COL_SENT, 1);
return db.update(Sqlite.TABLE_STATUSES_STORED,
values, Sqlite.COL_ID + " = ? ",
new String[]{String.valueOf(id)});
}
//------- REMOVE -------
/***
* Remove stored status by id
* @return int
*/
public int remove(long id){
return db.delete(Sqlite.TABLE_STATUSES_STORED, Sqlite.COL_ID + " = \"" + id + "\"", null);
}
public int removeAllDrafts(){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
String instance = Helper.getLiveInstance(context);
return db.delete(Sqlite.TABLE_STATUSES_STORED, Sqlite.COL_IS_SCHEDULED + " = \"0\" AND " + Sqlite.COL_USER_ID + " = '" + userId+ "' AND " + Sqlite.COL_INSTANCE + " = '" + instance+ "'", null);
}
//------- GETTERS -------
/**
* Returns all stored Statuses in db
* @return stored status List<StoredStatus>
*/
public List<StoredStatus> getAllStatus(){
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
String instance = Helper.getLiveInstance(context);
try {
Cursor c = db.query(Sqlite.TABLE_STATUSES_STORED, null, Sqlite.COL_USER_ID + " = '" + userId+ "' AND " + Sqlite.COL_INSTANCE + " = '" + instance+ "'", null, null, null, Sqlite.COL_DATE_CREATION + " DESC", null);
return cursorToListStatuses(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns all stored Statuses in db
* @return stored status List<StoredStatus>
*/
public List<StoredStatus> getAllDrafts(){
try {
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
String instance = Helper.getLiveInstance(context);
Cursor c = db.query(Sqlite.TABLE_STATUSES_STORED, null, Sqlite.COL_USER_ID + " = '" + userId+ "' AND " + Sqlite.COL_INSTANCE + " = '" + instance+ "' AND " + Sqlite.COL_IS_SCHEDULED + " = 0", null, null, null, Sqlite.COL_DATE_CREATION + " DESC", null);
return cursorToListStatuses(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns all not sent Statuses in db
* @return stored status List<StoredStatus>
*/
public List<StoredStatus> getAllNotSent(){
try {
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
String instance = Helper.getLiveInstance(context);
Cursor c = db.query(Sqlite.TABLE_STATUSES_STORED, null, Sqlite.COL_USER_ID + " = '" + userId+ "' AND " + Sqlite.COL_INSTANCE + " = '" + instance+ "' AND " +Sqlite.COL_IS_SCHEDULED + " = 1 AND " + Sqlite.COL_SENT + " = 0", null, null, null, Sqlite.COL_DATE_CREATION + " DESC", null);
return cursorToListStatuses(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns all sent Statuses in db
* @return stored status List<StoredStatus>
*/
public List<StoredStatus> getAllSent(){
try {
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
String instance = Helper.getLiveInstance(context);
Cursor c = db.query(Sqlite.TABLE_STATUSES_STORED, null, Sqlite.COL_USER_ID + " = '" + userId+ "' AND " + Sqlite.COL_INSTANCE + " = '" + instance+ "' AND " +Sqlite.COL_IS_SCHEDULED + " = 1 AND " + Sqlite.COL_SENT + " = 1", null, null, null, Sqlite.COL_DATE_CREATION + " DESC", null);
return cursorToListStatuses(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns a stored status by id in db
* @return stored status StoredStatus
*/
public StoredStatus getStatus(long id){
try {
Cursor c = db.query(Sqlite.TABLE_STATUSES_STORED, null, Sqlite.COL_ID + " = '" + id + "'", null, null, null, null, null);
return cursorToStoredStatus(c);
} catch (Exception e) {
return null;
}
}
/***
* Method to hydrate Stored statuses from database
* @param c Cursor
* @return StoredStatus
*/
private StoredStatus cursorToStoredStatus(Cursor c){
//No element found
if (c.getCount() == 0)
return null;
//Take the first element
c.moveToFirst();
//New user
StoredStatus storedStatus = new StoredStatus();
storedStatus.setId(c.getInt(c.getColumnIndex(Sqlite.COL_ID)));
Status status = Helper.restoreStatusFromString(c.getString(c.getColumnIndex(Sqlite.COL_STATUS_SERIALIZED)));
storedStatus.setStatus(status);
storedStatus.setSent(c.getInt(c.getColumnIndex(Sqlite.COL_SENT)) == 1);
storedStatus.setScheduled(c.getInt(c.getColumnIndex(Sqlite.COL_IS_SCHEDULED)) == 1);
storedStatus.setCreation_date(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_DATE_CREATION))));
storedStatus.setScheduled_date(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_DATE_SCHEDULED))));
storedStatus.setSent_date(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_DATE_SENT))));
//Close the cursor
c.close();
//Stored status is returned
return storedStatus;
}
/***
* Method to hydrate stored statuses from database
* @param c Cursor
* @return List<StoredStatus>
*/
private List<StoredStatus> cursorToListStatuses(Cursor c){
//No element found
if (c.getCount() == 0)
return null;
List<StoredStatus> storedStatuses = new ArrayList<>();
while (c.moveToNext() ) {
//Restore the status
StoredStatus storedStatus = new StoredStatus();
storedStatus.setId(c.getInt(c.getColumnIndex(Sqlite.COL_ID)));
Status status = Helper.restoreStatusFromString(c.getString(c.getColumnIndex(Sqlite.COL_STATUS_SERIALIZED)));
storedStatus.setStatus(status);
storedStatus.setSent(c.getInt(c.getColumnIndex(Sqlite.COL_SENT)) == 1);
storedStatus.setScheduled(c.getInt(c.getColumnIndex(Sqlite.COL_IS_SCHEDULED)) == 1);
storedStatus.setCreation_date(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_DATE_CREATION))));
storedStatus.setScheduled_date(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_DATE_SCHEDULED))));
storedStatus.setSent_date(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_DATE_SENT))));
storedStatuses.add(storedStatus);
}
//Close the cursor
c.close();
//Statuses list is returned
return storedStatuses;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Thomas Schneider
This file is a part of Mastalab
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.
Mastalab 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 Thomas Schneider; if not,
see <http://www.gnu.org/licenses>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="@+id/account_container"
android:orientation="vertical">
<TextView
android:id="@+id/draft_title"
android:textStyle="bold"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/draft_date"
android:textSize="12sp"
android:layout_marginTop="5dp"
android:textStyle="italic"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:gravity="end"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<ImageView
android:id="@+id/draft_delete"
android:src="@drawable/ic_cancel"
android:layout_gravity="center"
android:gravity="center"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="10dp"
tools:ignore="ContentDescription" />
</LinearLayout>

View File

@ -53,7 +53,12 @@
android:text="@string/set_display_reply"
android:layout_height="wrap_content" />
<CheckBox
android:layout_marginTop="10dp"
android:id="@+id/set_auto_store"
android:layout_width="wrap_content"
android:text="@string/set_auto_store_toot"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"

View File

@ -5,5 +5,20 @@
android:id="@+id/action_microphone"
android:title="@string/microphone"
android:icon="@drawable/ic_action_mic"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_store"
android:title="@string/save"
android:icon="@drawable/ic_save"
app:showAsAction="never" />
<item
android:id="@+id/action_restore"
android:title="@string/restore"
android:icon="@drawable/ic_restore"
app:showAsAction="never" />
<!--<item
android:id="@+id/action_schedule"
android:title="@string/schedule"
android:icon="@drawable/ic_schedule"
app:showAsAction="never" />-->
</menu>

View File

@ -28,6 +28,7 @@
<string name="tags">Tags</string>
<string name="token">Jeton</string>
<string name="save">Sauvegarder</string>
<string name="restore">Restaurer</string>
<string name="two_factor_authentification">Authentification en deux étapes ?</string>
<string name="other_instance">Autre instance que mastodon.etalab.gouv.fr ?</string>
<string name="no_result">Aucun résultat !</string>
@ -41,6 +42,8 @@
<string name="microphone">Microphone</string>
<string name="speech_prompt">Veuillez dire quelque chose</string>
<string name="speech_not_supported">Désolé ! Votre appareil ne supporte pas la commande vocale !</string>
<string name="delete_all">Tout effacer</string>
<string name="schedule">Programmer</string>
<!--- Menu -->
<string name="home_menu">Accueil</string>
<string name="local_menu">Fil public local</string>
@ -149,7 +152,9 @@
<item>N\'afficher que pour vos abonné(e)s</item>
<item>N\'afficher que pour les personnes mentionnées</item>
</string-array>
<string name="no_draft">Aucun brouillon !</string>
<string name="choose_toot">Choisissez un pouet</string>
<string name="remove_draft">Supprimer le brouillon ?</string>
<!-- Instance -->
<string name="instance_no_description">Aucune description !</string>
@ -215,6 +220,7 @@
<string name="nothing_to_do">Aucune action ne peut être réalisée</string>
<string name="toast_saved">Le média a été enregistré !</string>
<string name="toast_error_translate">Une erreur est survenue lors de la traduction !</string>
<string name="toast_toot_saved">Brouillon enregistré !</string>
<!-- Settings -->
<string name="settings_title_optimisation">Optimisation du chargement</string>
<string name="set_toots_page">Nombre de pouets par chargement</string>
@ -229,6 +235,7 @@
<string name="load_sensitive_attachment">Charger les images sensibles</string>
<string name="set_display_reply">Afficher le message précédent lors d\'une réponse</string>
<string name="set_folder_title">Destination : </string>
<string name="set_auto_store_toot">Enregistrer les brouillons automatiquement</string>
<string name="settings_title_notifications">Gestion des notifications</string>
<string name="set_notif_follow">Notifier lorsque quelquun me suit</string>

View File

@ -29,6 +29,7 @@
<string name="tags">Tags</string>
<string name="token">Token</string>
<string name="save">Save</string>
<string name="restore">Restore</string>
<string name="two_factor_authentification">Two-step authentication?</string>
<string name="other_instance">Other instance than mastodon.etalab.gouv.fr?</string>
<string name="no_result">No results!</string>
@ -42,7 +43,9 @@
<string name="microphone">Microphone</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
<string name="schedule">Schedule</string>
<!--- Menu -->
<string name="home_menu">Home</string>
<string name="local_menu">Local timeline</string>
@ -152,6 +155,9 @@
<item>Post to mentioned users only</item>
</string-array>
<string name="no_draft">No draft!</string>
<string name="choose_toot">Choose a toot</string>
<string name="remove_draft">Remove draft?</string>
<!-- Instance -->
<string name="instance_no_description">No description available!</string>
@ -218,6 +224,8 @@
<string name="nothing_to_do">No action can be taken</string>
<string name="toast_saved">The media has been saved!</string>
<string name="toast_error_translate">An error occurred while translating!</string>
<string name="toast_toot_saved">Draft saved!</string>
<!-- Settings -->
<string name="settings_title_optimisation">Optimisation of loading</string>
<string name="set_toots_page">Number of toots per load</string>
@ -232,7 +240,7 @@
<string name="load_sensitive_attachment">Sensitive content</string>
<string name="set_display_reply">Display previous message in responses</string>
<string name="set_folder_title">Path: </string>
<string name="set_auto_store_toot">Save drafts automatically</string>
<string name="settings_title_notifications">Manage notifications</string>
<string name="set_notif_follow">Notify when someone follows you</string>
<string name="set_notif_follow_ask">Notify when someone requests to follow you</string>