diff --git a/app/build.gradle b/app/build.gradle
index cfc1fe8ec..46db1be3b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -55,4 +55,10 @@ dependencies {
}
compile 'org.bouncycastle:bcprov-jdk15on:1.57'
testCompile 'junit:junit:4.12'
+
+ //room
+ compile "android.arch.persistence.room:runtime:1.0.0-alpha3"
+ annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha3"
+ compile "android.arch.persistence.room:rxjava2:1.0.0-alpha2"
+
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1bb3c925d..bafc4abd6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,6 +26,10 @@
+
+
diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java
index e8e627984..1ed2255e2 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java
@@ -75,7 +75,12 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+import android.widget.Toast;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.keylesspalace.tusky.db.TootDao;
+import com.keylesspalace.tusky.db.TootEntity;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Media;
import com.keylesspalace.tusky.entity.Status;
@@ -122,6 +127,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm
private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;
private static final int COMPOSE_SUCCESS = -1;
private static final int THUMBNAIL_SIZE = 128; // pixels
+ private static TootDao tootDao = TuskyApplication.getDB().tootDao();
private EditTextTyped textEditor;
private LinearLayout mediaPreviewBar;
@@ -148,6 +154,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm
private int currentFlags;
private Uri photoUploadUri;
+
/**
* The Target object must be stored as a member field or method and cannot be an anonymous class otherwise this won't work as expected. The reason is that Picasso accepts this parameter as a weak memory reference. Because anonymous classes are eligible for garbage collection when there are no more references, the network request to fetch the image may finish after this anonymous class has already been reclaimed. See this Stack Overflow discussion for more details.
*/
@@ -191,6 +198,16 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm
onSendClicked();
}
});
+ floatingBtn.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ boolean b = saveTheToot(textEditor.getText().toString());
+ if (b) {
+ Toast.makeText(ComposeActivity.this, R.string.action_save_one_toot, Toast.LENGTH_SHORT).show();
+ }
+ return b;
+ }
+ });
pickBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -278,6 +295,22 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm
startingContentWarning = intent.getStringExtra("content_warning");
}
}
+
+ /* If come from SavedTootActivity
+ * */
+ String savedTootText = intent.getStringExtra("saved_toot_text");
+ if (!TextUtils.isEmpty(savedTootText)) {
+ textEditor.append(savedTootText);
+ }
+
+ String savedJsonUrls = intent.getStringExtra("saved_json_urls");
+ if (!TextUtils.isEmpty(savedJsonUrls)) {
+ // try to redo a list of media
+ ArrayList playersList = new Gson().fromJson(savedJsonUrls,
+ new TypeToken>() {
+ }.getType());
+
+ }
}
/* If the currently logged in account is locked, its posts should default to private. This
@@ -442,7 +475,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm
}
private void doErrorDialog(@StringRes int descriptionId, @StringRes int actionId,
- View.OnClickListener listener) {
+ View.OnClickListener listener) {
Snackbar bar = Snackbar.make(findViewById(R.id.activity_compose), getString(descriptionId),
Snackbar.LENGTH_SHORT);
bar.setAction(actionId, listener);
@@ -493,6 +526,33 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm
}
}
+ public boolean saveTheToot(String s) {
+ if (TextUtils.isEmpty(s)) {
+ return false;
+ } else {
+ final TootEntity toot = new TootEntity();
+ toot.setText(s);
+ if (mediaQueued != null && mediaQueued.size() > 0) {
+ List list = new ArrayList<>();
+ for (QueuedMedia q :
+ mediaQueued) {
+ list.add(q.uri.toString());
+ }
+ String json = new Gson().toJson(list);
+ toot.setUrls(json);
+ }
+
+ new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ tootDao.insert(toot);
+ return null;
+ }
+ }.execute();
+ return true;
+ }
+ }
+
private void setStatusVisibility(String visibility) {
statusVisibility = visibility;
switch (visibility) {
@@ -1355,7 +1415,9 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm
private class MentionAutoCompleteAdapter extends ArrayAdapter implements Filterable {
private ArrayList resultList;
- private @LayoutRes int layoutId;
+ private
+ @LayoutRes
+ int layoutId;
MentionAutoCompleteAdapter(Context context, @LayoutRes int resource) {
super(context, resource);
diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
index 4b2958a13..7423d0f4d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
@@ -65,7 +65,6 @@ import retrofit2.Response;
public class MainActivity extends BaseActivity {
private static final String TAG = "MainActivity"; // logging tag
- protected static int COMPOSE_RESULT = 1;
private static final long DRAWER_ITEM_EDIT_PROFILE = 0;
private static final long DRAWER_ITEM_FAVOURITES = 1;
private static final long DRAWER_ITEM_MUTED_USERS = 2;
@@ -75,7 +74,10 @@ public class MainActivity extends BaseActivity {
private static final long DRAWER_ITEM_ABOUT = 6;
private static final long DRAWER_ITEM_LOG_OUT = 7;
private static final long DRAWER_ITEM_FOLLOW_REQUESTS = 8;
+ private static final long DRAWER_ITEM_SAVED_TOOT = 9;
+ protected static int COMPOSE_RESULT = 1;
+ public FloatingActionButton composeButton;
private String loggedInAccountId;
private String loggedInAccountUsername;
private Stack pageHistory;
@@ -83,8 +85,6 @@ public class MainActivity extends BaseActivity {
private Drawer drawer;
private ViewPager viewPager;
- public FloatingActionButton composeButton;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -179,7 +179,8 @@ public class MainActivity extends BaseActivity {
}
@Override
- public void onTabReselected(TabLayout.Tab tab) {}
+ public void onTabReselected(TabLayout.Tab tab) {
+ }
});
Intent intent = getIntent();
@@ -289,23 +290,28 @@ public class MainActivity extends BaseActivity {
R.drawable.ic_mute_24dp, getTheme());
ThemeUtils.setDrawableTint(this, muteDrawable, R.attr.toolbar_icon_tint);
+ List listItem = new ArrayList<>();
+ listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_EDIT_PROFILE).withName(getString(R.string.action_edit_profile)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_person));
+ listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_FAVOURITES).withName(getString(R.string.action_view_favourites)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_star));
+ listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_MUTED_USERS).withName(getString(R.string.action_view_mutes)).withSelectable(false).withIcon(muteDrawable));
+ listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_BLOCKED_USERS).withName(getString(R.string.action_view_blocks)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_block));
+ listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SEARCH).withName(getString(R.string.action_search)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_search));
+ listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SAVED_TOOT).withName(getString(R.string.action_access_saved_toot)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_save));
+ listItem.add(new DividerDrawerItem());
+ listItem.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_PREFERENCES).withName(getString(R.string.action_view_preferences)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_settings));
+ listItem.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_ABOUT).withName(getString(R.string.about_title_activity)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_info));
+ listItem.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_LOG_OUT).withName(getString(R.string.action_logout)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_exit_to_app));
+
+ IDrawerItem[] array = new IDrawerItem[listItem.size()];
+ listItem.toArray(array); // fill the array
+
drawer = new DrawerBuilder()
.withActivity(this)
//.withToolbar(toolbar)
.withAccountHeader(headerResult)
.withHasStableIds(true)
.withSelectedItem(-1)
- .addDrawerItems(
- new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_EDIT_PROFILE).withName(getString(R.string.action_edit_profile)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_person),
- new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_FAVOURITES).withName(getString(R.string.action_view_favourites)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_star),
- new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_MUTED_USERS).withName(getString(R.string.action_view_mutes)).withSelectable(false).withIcon(muteDrawable),
- new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_BLOCKED_USERS).withName(getString(R.string.action_view_blocks)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_block),
- new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SEARCH).withName(getString(R.string.action_search)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_search),
- new DividerDrawerItem(),
- new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_PREFERENCES).withName(getString(R.string.action_view_preferences)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_settings),
- new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_ABOUT).withName(getString(R.string.about_title_activity)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_info),
- new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_LOG_OUT).withName(getString(R.string.action_logout)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_exit_to_app)
- )
+ .addDrawerItems(array)
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
@Override
public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
@@ -341,6 +347,9 @@ public class MainActivity extends BaseActivity {
Intent intent = new Intent(MainActivity.this, AccountListActivity.class);
intent.putExtra("type", AccountListActivity.Type.FOLLOW_REQUESTS);
startActivity(intent);
+ } else if (drawerItemIdentifier == DRAWER_ITEM_SAVED_TOOT) {
+ Intent intent = new Intent(MainActivity.this, SavedTootActivity.class);
+ startActivity(intent);
}
}
@@ -469,9 +478,9 @@ public class MainActivity extends BaseActivity {
@Override
public void onBackPressed() {
- if(drawer != null && drawer.isDrawerOpen()) {
+ if (drawer != null && drawer.isDrawerOpen()) {
drawer.closeDrawer();
- } else if(pageHistory.size() < 2) {
+ } else if (pageHistory.size() < 2) {
super.onBackPressed();
} else {
pageHistory.pop();
diff --git a/app/src/main/java/com/keylesspalace/tusky/SavedTootActivity.java b/app/src/main/java/com/keylesspalace/tusky/SavedTootActivity.java
new file mode 100644
index 000000000..88560dab2
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/SavedTootActivity.java
@@ -0,0 +1,133 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.widget.DividerItemDecoration;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.TextView;
+
+import com.keylesspalace.tusky.adapter.SavedTootAdapter;
+import com.keylesspalace.tusky.db.TootDao;
+import com.keylesspalace.tusky.db.TootEntity;
+import com.keylesspalace.tusky.util.ThemeUtils;
+
+import java.util.List;
+
+public class SavedTootActivity extends BaseActivity implements SavedTootAdapter.SavedTootAction {
+
+ // dao
+ private static TootDao tootDao = TuskyApplication.getDB().tootDao();
+
+ // ui
+ private SavedTootAdapter adapter;
+ private TextView noContent;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_saved_toot);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ ActionBar bar = getSupportActionBar();
+ if (bar != null) {
+ bar.setTitle(getString(R.string.title_saved_toot));
+ bar.setDisplayHomeAsUpEnabled(true);
+ bar.setDisplayShowHomeEnabled(true);
+ }
+
+ RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
+ noContent = (TextView) findViewById(R.id.no_content);
+ recyclerView.setHasFixedSize(true);
+ LinearLayoutManager layoutManager = new LinearLayoutManager(this);
+ recyclerView.setLayoutManager(layoutManager);
+ DividerItemDecoration divider = new DividerItemDecoration(
+ this, layoutManager.getOrientation());
+ Drawable drawable = ThemeUtils.getDrawable(this, R.attr.status_divider_drawable,
+ R.drawable.status_divider_dark);
+ divider.setDrawable(drawable);
+ recyclerView.addItemDecoration(divider);
+ adapter = new SavedTootAdapter(this);
+ recyclerView.setAdapter(adapter);
+
+ // req
+ getAllToot();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ onBackPressed();
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ public void getAllToot() {
+ new AsyncTask>() {
+ @Override
+ protected List doInBackground(Void... params) {
+ return tootDao.loadAll();
+ }
+
+ @Override
+ protected void onPostExecute(List tootEntities) {
+ super.onPostExecute(tootEntities);
+ // set ui
+ setNoContent(tootEntities.size());
+ adapter.addItems(tootEntities);
+ }
+ }.execute();
+ }
+
+ private void setNoContent(int size) {
+ if (size == 0) {
+ noContent.setVisibility(View.VISIBLE);
+ } else {
+ noContent.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @Override
+ public void delete(int position, TootEntity item) {
+ // update DB
+ tootDao.delete(item);
+ // update adapter
+ if (adapter != null) {
+ adapter.removeItem(position);
+ setNoContent(adapter.getItemCount());
+ }
+ }
+
+ @Override
+ public void click(int position, TootEntity item) {
+ Intent intent = new Intent(this, ComposeActivity.class);
+ intent.putExtra("saved_toot_text", item.getText());
+ intent.putExtra("saved_json_urls", item.getUrls());
+ startActivity(intent);
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
index a48185a34..a58857ee1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
+++ b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
@@ -16,12 +16,14 @@
package com.keylesspalace.tusky;
import android.app.Application;
+import android.arch.persistence.room.Room;
import android.net.Uri;
import android.util.Log;
+import com.jakewharton.picasso.OkHttp3Downloader;
+import com.keylesspalace.tusky.db.AppDatabase;
import com.keylesspalace.tusky.util.OkHttpUtils;
import com.squareup.picasso.Picasso;
-import com.jakewharton.picasso.OkHttp3Downloader;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -30,6 +32,11 @@ import java.security.Security;
public class TuskyApplication extends Application {
private static final String TAG = "TuskyApplication"; // logging tag
+ private static AppDatabase db;
+
+ public static AppDatabase getDB() {
+ return db;
+ }
@Override
public void onCreate() {
@@ -84,5 +91,8 @@ public class TuskyApplication extends Application {
}
}
}
+
+ db = Room.databaseBuilder(getApplicationContext(),
+ AppDatabase.class, "tuskyDB").allowMainThreadQueries().build();
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/SavedTootAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/SavedTootAdapter.java
new file mode 100644
index 000000000..3db08bc0c
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/SavedTootAdapter.java
@@ -0,0 +1,134 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * This file is a part of Tusky.
+ *
+ * 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.
+ *
+ * Tusky 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 Tusky; if not,
+ * see . */
+
+package com.keylesspalace.tusky.adapter;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.db.TootEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SavedTootAdapter extends RecyclerView.Adapter {
+ private List list;
+ private SavedTootAction handler;
+
+ public SavedTootAdapter(Context context) {
+ super();
+ list = new ArrayList<>();
+ handler = (SavedTootAction) context;
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_saved_toot, parent, false);
+ return new TootViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
+ TootViewHolder holder = (TootViewHolder) viewHolder;
+ holder.bind(position, getItem(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return list.size();
+ }
+
+ public void addItems(List newToot) {
+ int end = list.size();
+ list.addAll(newToot);
+ notifyItemRangeInserted(end, newToot.size());
+ }
+
+ @Nullable
+ public TootEntity removeItem(int position) {
+ if (position < 0 || position >= list.size()) {
+ return null;
+ }
+ TootEntity toot = list.remove(position);
+ notifyItemRemoved(position);
+ return toot;
+ }
+
+ public TootEntity getItem(int position) {
+ if (position >= 0 && position < list.size()) {
+ return list.get(position);
+ }
+ return null;
+ }
+
+ // handler saved toot
+ public interface SavedTootAction {
+ void delete(int position, TootEntity item);
+
+ void click(int position, TootEntity item);
+ }
+
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ TextView mTextView;
+
+ public ViewHolder(TextView v) {
+ super(v);
+ mTextView = v;
+ }
+ }
+
+ private class TootViewHolder extends RecyclerView.ViewHolder {
+ View view;
+ TextView content;
+ ImageButton suppr;
+
+ TootViewHolder(View view) {
+ super(view);
+ this.view = view;
+ this.content = (TextView) view.findViewById(R.id.content);
+ this.suppr = (ImageButton) view.findViewById(R.id.suppr);
+ }
+
+ void bind(final int position, final TootEntity item) {
+ if (item != null) {
+ if (!TextUtils.isEmpty(item.getText()))
+ content.setText(item.getText());
+ else
+ content.setText("");
+ suppr.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ handler.delete(position, item);
+ }
+ });
+ view.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ handler.click(position, item);
+ }
+ });
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java b/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
new file mode 100644
index 000000000..8480d27e6
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
@@ -0,0 +1,14 @@
+package com.keylesspalace.tusky.db;
+
+import android.arch.persistence.room.Database;
+import android.arch.persistence.room.RoomDatabase;
+
+/**
+ * DB version & declare DAO
+ */
+
+@Database(entities = {TootEntity.class}, version = 1, exportSchema = false)
+public abstract class AppDatabase extends RoomDatabase {
+
+ public abstract TootDao tootDao();
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/MediaEntity.java b/app/src/main/java/com/keylesspalace/tusky/db/MediaEntity.java
new file mode 100644
index 000000000..398b1d1ce
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/db/MediaEntity.java
@@ -0,0 +1,47 @@
+package com.keylesspalace.tusky.db;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.ForeignKey;
+import android.arch.persistence.room.PrimaryKey;
+
+/**
+ * Media model
+ */
+
+@Entity(foreignKeys = @ForeignKey(entity = TootEntity.class,
+ parentColumns = "uid",
+ childColumns = "toot_id"))
+public class MediaEntity {
+ @ColumnInfo(name = "toot_id")
+ private int toot_id;
+ @PrimaryKey(autoGenerate = true)
+ private int uid;
+ @ColumnInfo(name = "url")
+ private String url;
+
+ // getter setter
+ public int getToot_id() {
+ return toot_id;
+ }
+
+ public void setToot_id(int toot_id) {
+ this.toot_id = toot_id;
+ }
+
+ public int getUid() {
+ return uid;
+ }
+
+ public void setUid(int uid) {
+ this.uid = uid;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/TootDao.java b/app/src/main/java/com/keylesspalace/tusky/db/TootDao.java
new file mode 100644
index 000000000..19461984a
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/db/TootDao.java
@@ -0,0 +1,36 @@
+package com.keylesspalace.tusky.db;
+
+import android.arch.persistence.room.Dao;
+import android.arch.persistence.room.Delete;
+import android.arch.persistence.room.Insert;
+import android.arch.persistence.room.Query;
+import android.arch.persistence.room.Update;
+
+import java.util.List;
+
+/**
+ * Created by cto3543 on 28/06/2017.
+ * crud interface on this Toot DB
+ */
+
+@Dao
+public interface TootDao {
+ // c
+ @Insert
+ long insert(TootEntity users);
+
+ // r
+ @Query("SELECT * FROM TootEntity")
+ List loadAll();
+
+ @Query("SELECT * FROM TootEntity WHERE uid IN (:uid)")
+ List loadAllByTootId(int... uid);
+
+ // u
+ @Update
+ void updateToot(TootEntity... toot);
+
+ // d
+ @Delete
+ int delete(TootEntity user);
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/TootEntity.java b/app/src/main/java/com/keylesspalace/tusky/db/TootEntity.java
new file mode 100644
index 000000000..760379e86
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/db/TootEntity.java
@@ -0,0 +1,46 @@
+package com.keylesspalace.tusky.db;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.PrimaryKey;
+
+/**
+ * toot model
+ */
+
+@Entity
+public class TootEntity {
+ @PrimaryKey(autoGenerate = true)
+ private int uid;
+
+ @ColumnInfo(name = "text")
+ private String text;
+
+ @ColumnInfo(name = "urls")
+ private String urls;
+
+ // getter setter
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public int getUid() {
+ return uid;
+ }
+
+ public void setUid(int uid) {
+ this.uid = uid;
+ }
+
+ public String getUrls() {
+ return urls;
+ }
+
+ public void setUrls(String urls) {
+ this.urls = urls;
+ }
+}
diff --git a/app/src/main/res/layout/activity_saved_toot.xml b/app/src/main/res/layout/activity_saved_toot.xml
new file mode 100644
index 000000000..718273bc6
--- /dev/null
+++ b/app/src/main/res/layout/activity_saved_toot.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_saved_toot.xml b/app/src/main/res/layout/item_saved_toot.xml
new file mode 100644
index 000000000..cf76d824f
--- /dev/null
+++ b/app/src/main/res/layout/item_saved_toot.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index fe95f74cd..518ce9f7c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -32,6 +32,7 @@
Blocked users
Follow Requests
Edit your profile
+ Saved Toot
\@%s
%s boosted
@@ -98,6 +99,7 @@
Accept
Reject
Search
+ Drafts
Share toot URL to…
Share toot to…
@@ -191,4 +193,9 @@
Video
Follow requested
+
+ %1$s %2$s
+ no content
+ Toot saved !
+
diff --git a/build.gradle b/build.gradle
index 0a26ece58..eb17a91de 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,6 +16,7 @@ allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
+ maven { url 'https://maven.google.com' }
}
}