1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-01 17:26:46 +01:00

removed donation link (still not work though! fuck google!)

use trigger to remove duplicate statuses, which makes refresh faster.
added database inspector for debug build
This commit is contained in:
Mariotaku Lee 2015-04-01 00:39:14 +08:00
parent d198e7dec5
commit 0a18f26224
17 changed files with 172 additions and 295 deletions

View File

@ -52,6 +52,7 @@ public interface IntentConstants {
public static final String INTENT_ACTION_COMPOSE_PICK_IMAGE = INTENT_PACKAGE_PREFIX + "COMPOSE_PICK_IMAGE";
public static final String INTENT_ACTION_TAKE_PHOTO = INTENT_PACKAGE_PREFIX + "TAKE_PHOTO";
public static final String INTENT_ACTION_PICK_IMAGE = INTENT_PACKAGE_PREFIX + "PICK_IMAGE";
public static final String INTENT_ACTION_HIDDEN_SETTINGS_ENTRY = INTENT_PACKAGE_PREFIX + "HIDDEN_SETTINGS_ENTRY";
public static final String INTENT_ACTION_EXTENSION_EDIT_IMAGE = INTENT_PACKAGE_PREFIX + "EXTENSION_EDIT_IMAGE";
public static final String INTENT_ACTION_EXTENSION_UPLOAD = INTENT_PACKAGE_PREFIX + "EXTENSION_UPLOAD";

View File

@ -6,6 +6,10 @@ public class SQLFunctions {
return String.format("SUM (%s)", val);
}
public static String COUNT() {
return COUNT("*");
}
public static String COUNT(final String val) {
return String.format("COUNT (%s)", val);
}

View File

@ -32,6 +32,7 @@ import org.mariotaku.querybuilder.query.SQLCreateIndexQuery;
import org.mariotaku.querybuilder.query.SQLCreateTableQuery;
import org.mariotaku.querybuilder.query.SQLCreateTriggerQuery;
import org.mariotaku.querybuilder.query.SQLCreateViewQuery;
import org.mariotaku.querybuilder.query.SQLDeleteQuery;
import org.mariotaku.querybuilder.query.SQLDropTableQuery;
import org.mariotaku.querybuilder.query.SQLDropTriggerQuery;
import org.mariotaku.querybuilder.query.SQLDropViewQuery;
@ -84,6 +85,10 @@ public class SQLQueryBuilder {
return createView(false, false, name);
}
public static SQLDeleteQuery.Builder deleteFrom(Table table) {
return new SQLDeleteQuery.Builder().from(table);
}
public static SQLDropTableQuery dropTable(final boolean dropIfExists, final String table) {
return new SQLDropTableQuery(dropIfExists, table);
}

View File

@ -2,19 +2,20 @@ package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Table;
public class SQLDeleteQuery implements SQLQuery {
private String table;
private Table table;
private Expression where;
@Override
public String getSQL() {
if (where != null) return String.format("DELETE FROM %s", table);
return String.format("DELETE FROM %S WHERE %s", table, where.getSQL());
if (where == null) return String.format("DELETE FROM %s", table.getSQL());
return String.format("DELETE FROM %S WHERE %s", table.getSQL(), where.getSQL());
}
void setFrom(final String table) {
void setFrom(final Table table) {
this.table = table;
}
@ -37,7 +38,7 @@ public class SQLDeleteQuery implements SQLQuery {
return build().getSQL();
}
public Builder from(final String table) {
public Builder from(final Table table) {
checkNotBuilt();
query.setFrom(table);
return this;

View File

@ -26,8 +26,8 @@ android {
applicationId "org.mariotaku.twidere.extension.streaming"
minSdkVersion 14
targetSdkVersion 22
versionCode 13
versionName "1.11 (0.3.0-dev)"
versionCode 14
versionName "1.12 (0.3.0-dev)"
}
buildTypes {
release {

View File

@ -10,7 +10,7 @@ android {
applicationId "org.mariotaku.twidere"
minSdkVersion 14
targetSdkVersion 22
versionCode 101
versionCode 102
versionName "0.3.0"
multiDexEnabled true
}
@ -89,6 +89,7 @@ dependencies {
googleCompile 'com.google.maps.android:android-maps-utils:0.3.4'
fdroidCompile 'org.osmdroid:osmdroid-android:4.3'
fdroidCompile 'org.slf4j:slf4j-simple:1.7.12'
debugCompile 'im.dino:dbinspector:3.1.0@aar'
compile project(':twidere.component.common')
compile project(':twidere.component.nyan')
compile fileTree(dir: 'libs/main', include: ['*.jar'])

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ 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, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity
android:name="im.dino.dbinspector.activities.DbInspectorActivity"
android:label="Database Inspector">
<intent-filter tools:node="removeAll">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="org.mariotaku.twidere.HIDDEN_SETTINGS_ENTRY"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -33,7 +33,7 @@ import static org.mariotaku.twidere.annotation.Preference.Type.STRING;
public interface Constants extends TwidereConstants {
String DATABASES_NAME = "twidere.sqlite";
int DATABASES_VERSION = 88;
int DATABASES_VERSION = 89;
int MENU_GROUP_STATUS_EXTENSION = 10;
int MENU_GROUP_COMPOSE_EXTENSION = 11;

View File

@ -1,114 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.ParseUtils;
import java.text.NumberFormat;
import java.text.ParseException;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.Utils.getDefaultAccountScreenName;
public class PayPalDonateFragment extends BaseFragment implements OnClickListener, TextWatcher {
private EditText mEditName, mEditAmount;
private Button mDonateButton;
@Override
public void afterTextChanged(final Editable s) {
}
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mEditName.setText(getDefaultAccountScreenName(getActivity()));
mEditAmount.addTextChangedListener(this);
mDonateButton.setOnClickListener(this);
mDonateButton.setEnabled(false);
}
@Override
public void onClick(final View view) {
switch (view.getId()) {
case R.id.donate: {
final String amount = ParseUtils.parseString(mEditAmount.getText());
if (isEmpty(amount)) return;
final String name = ParseUtils.parseString(mEditName.getText());
final Uri.Builder builder = Uri.parse("https://www.paypal.com/cgi-bin/webscr").buildUpon();
builder.appendQueryParameter("cmd", "_xclick");
builder.appendQueryParameter("business", "mariotaku.lee@gmail.com");
builder.appendQueryParameter("amount", amount);
if (isEmpty(name)) {
builder.appendQueryParameter("item_name", "Twidere donation");
} else {
builder.appendQueryParameter("item_name", String.format("Twidere donation by %s", name));
}
startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
getActivity().onBackPressed();
break;
}
}
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_donate, container, false);
mEditName = (EditText) view.findViewById(R.id.name);
mEditAmount = (EditText) view.findViewById(R.id.amount);
mDonateButton = (Button) view.findViewById(R.id.donate);
return view;
}
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
if (isEmpty(s)) {
mDonateButton.setEnabled(false);
return;
}
final NumberFormat format = NumberFormat.getInstance(getResources().getConfiguration().locale);
try {
final Number number = format.parse(ParseUtils.parseString(s));
mDonateButton.setEnabled(number.doubleValue() > 0);
} catch (final ParseException e) {
mDonateButton.setEnabled(false);
}
}
}

View File

@ -19,33 +19,55 @@
package org.mariotaku.twidere.fragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import org.mariotaku.twidere.util.Utils;
public class SettingsDetailsFragment extends BasePreferenceFragment {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final PreferenceScreen screen = getPreferenceScreen();
if (screen != null) {
screen.removeAll();
}
final Bundle args = getArguments();
final Object rawResId = args.get(EXTRA_RESID);
final int resId;
if (rawResId instanceof Integer) {
resId = (Integer) rawResId;
} else if (rawResId instanceof String) {
resId = Utils.getResId(getActivity(), (String) rawResId);
} else {
resId = 0;
}
if (resId != 0) {
addPreferencesFromResource(resId);
}
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final PreferenceScreen defaultScreen = getPreferenceScreen();
final PreferenceScreen preferenceScreen;
if (defaultScreen != null) {
defaultScreen.removeAll();
preferenceScreen = defaultScreen;
} else {
preferenceScreen = getPreferenceManager().createPreferenceScreen(getActivity());
}
setPreferenceScreen(preferenceScreen);
final Bundle args = getArguments();
final Object rawResId = args.get(EXTRA_RESID);
final int resId;
if (rawResId instanceof Integer) {
resId = (Integer) rawResId;
} else if (rawResId instanceof String) {
resId = Utils.getResId(getActivity(), (String) rawResId);
} else {
resId = 0;
}
if (resId != 0) {
addPreferencesFromResource(resId);
}
final Context context = preferenceScreen.getContext();
final Intent hiddenEntryIntent = new Intent(INTENT_ACTION_HIDDEN_SETTINGS_ENTRY);
final PackageManager pm = context.getPackageManager();
for (ResolveInfo info : pm.queryIntentActivities(hiddenEntryIntent, PackageManager.MATCH_DEFAULT_ONLY)) {
final Preference preference = new Preference(context);
final Intent intent = new Intent(INTENT_ACTION_HIDDEN_SETTINGS_ENTRY);
intent.setPackage(info.resolvePackageName);
intent.setClassName(info.activityInfo.packageName, info.activityInfo.name);
preference.setIntent(intent);
preference.setTitle(info.loadLabel(pm));
preferenceScreen.addPreference(preference);
}
}
}

View File

@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.SettingsActivity;
import org.mariotaku.twidere.constant.IntentConstants;
@ -38,6 +39,10 @@ public class SecretCodeBroadcastReceiver extends BroadcastReceiver implements In
final String title = context.getString(R.string.hidden_settings);
final Bundle args = new Bundle();
args.putInt(EXTRA_RESID, R.xml.preferences_hidden);
final Intent hiddenEntryIntent = new Intent(INTENT_ACTION_HIDDEN_SETTINGS_ENTRY);
hiddenEntryIntent.setPackage(BuildConfig.APPLICATION_ID);
hiddenEntryIntent.addCategory(Intent.CATEGORY_DEFAULT);
args.putParcelable(EXTRA_INTENT, hiddenEntryIntent);
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, cls);
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);

View File

@ -25,6 +25,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@ -38,6 +39,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.SQLFunctions;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ListResponse;
@ -2046,50 +2048,57 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
// new CacheUsersStatusesTask(mContext, responses.toArray(array)).executeTask();
}
private boolean storeStatus(long accountId, List<twitter4j.Status> statuses, long maxId, boolean truncated, boolean notify) {
if (statuses == null || statuses.isEmpty()) {
return true;
private void storeStatus(long accountId, List<twitter4j.Status> statuses, long maxId, boolean truncated, boolean notify) {
if (statuses == null || statuses.isEmpty() || accountId <= 0) {
return;
}
final Uri uri = getDatabaseUri();
final boolean noItemsBefore = getStatusCountInDatabase(mContext, uri, accountId) <= 0;
final ContentValues[] values = new ContentValues[statuses.size()];
final long[] statusIds = new long[statuses.size()];
long minId = -1;
int minIdx = -1;
for (int i = 0, j = statuses.size(); i < j; i++) {
final twitter4j.Status status = statuses.get(i);
values[i] = createStatus(status, accountId);
statusIds[i] = status.getId();
final long id = status.getId();
if (minId == -1 || id < minId) {
minId = id;
minIdx = i;
}
statusIds[i] = id;
}
// Delete all rows conflicting before new data inserted.
final Expression accountWhere = Expression.equals(Statuses.ACCOUNT_ID, accountId);
final Expression statusWhere = Expression.in(new Column(Statuses.STATUS_ID), new RawItemArray(statusIds));
final String deleteWhere = Expression.and(accountWhere, statusWhere).getSQL();
final Uri deleteUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, false);
final int rowsDeleted = mResolver.delete(deleteUri, deleteWhere, null);
final String countWhere = Expression.and(accountWhere, statusWhere).getSQL();
final String[] projection = {SQLFunctions.COUNT()};
final int rowsDeleted;
final Cursor countCur = mResolver.query(uri, projection, countWhere, null, null);
if (countCur.moveToFirst()) {
rowsDeleted = countCur.getInt(0);
} else {
rowsDeleted = 0;
}
countCur.close();
// UCD
ProfilingUtil.profile(mContext, accountId,
"Download tweets, " + TwidereArrayUtils.toString(statusIds, ',', true));
ProfilingUtil.profile(mContext, accountId, "Download tweets, " + TwidereArrayUtils.toString(statusIds, ',', true));
//spice
SpiceProfilingUtil.profile(mContext, accountId, accountId + ",Refresh," + TwidereArrayUtils.toString(statusIds, ',', true));
//end
// Insert previously fetched items.
final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
bulkInsert(mResolver, insertUri, values);
// Insert a gap.
final long minId = statusIds.length != 0 ? TwidereArrayUtils.min(statusIds) : -1;
final boolean deletedOldGap = rowsDeleted > 0 && ArrayUtils.contains(statusIds, maxId);
final boolean noRowsDeleted = rowsDeleted == 0;
final boolean insertGap = minId > 0 && (noRowsDeleted || deletedOldGap) && !truncated
&& !noItemsBefore && statuses.size() > 1;
if (insertGap) {
final ContentValues gapValue = new ContentValues();
gapValue.put(Statuses.IS_GAP, 1);
final Expression where = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, accountId),
Expression.equals(Statuses.STATUS_ID, minId));
final Uri updateUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, true);
mResolver.update(updateUri, gapValue, where.getSQL(), null);
if (insertGap && minIdx != -1) {
values[minIdx].put(Statuses.IS_GAP, true);
}
return false;
// Insert previously fetched items.
final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
bulkInsert(mResolver, insertUri, values);
}
protected abstract Uri getDatabaseUri();

View File

@ -2195,11 +2195,11 @@ public final class Utils implements Constants, TwitterConstants {
return share_format.replace(FORMAT_PATTERN_TITLE, title).replace(FORMAT_PATTERN_TEXT, text != null ? text : "");
}
public static int getStatusCountInDatabase(final Context context, final Uri uri, final long account_id) {
public static int getStatusCountInDatabase(final Context context, final Uri uri, final long accountId) {
if (context == null) return -1;
final ContentResolver resolver = context.getContentResolver();
final String where = Statuses.ACCOUNT_ID + " = " + account_id;
final String[] projection = new String[]{SQLFunctions.COUNT(Statuses.STATUS_ID)};
final String where = Expression.equals(Statuses.ACCOUNT_ID, accountId).getSQL();
final String[] projection = new String[]{SQLFunctions.COUNT()};
final Cursor cur = ContentResolverUtils.query(resolver, uri, projection, where, null, null);
if (cur == null) return -1;
try {

View File

@ -27,12 +27,17 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.NewColumn;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.SQLQueryBuilder;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.query.SQLCreateIndexQuery;
import org.mariotaku.querybuilder.query.SQLCreateTableQuery;
import org.mariotaku.querybuilder.query.SQLCreateViewQuery;
import org.mariotaku.querybuilder.query.SQLCreateTriggerQuery.Event;
import org.mariotaku.querybuilder.query.SQLCreateTriggerQuery.Type;
import org.mariotaku.querybuilder.query.SQLDeleteQuery;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;
@ -91,7 +96,7 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
db.execSQL(createTable(SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true));
createViews(db);
createTriggers(db);
createIndices(db);
db.setTransactionSuccessful();
@ -107,8 +112,26 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
}
private void createViews(SQLiteDatabase db) {
db.execSQL(createDirectMessagesView().getSQL());
db.execSQL(createDirectMessageConversationEntriesView().getSQL());
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.TABLE_NAME)
.as(DirectMessagesQueryBuilder.build()).buildSQL());
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.ConversationEntries.TABLE_NAME)
.as(ConversationsEntryQueryBuilder.build()).buildSQL());
}
private void createTriggers(SQLiteDatabase db) {
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_statuses", Statuses.TABLE_NAME).getSQL());
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_mentions", Mentions.TABLE_NAME).getSQL());
}
private SQLQuery createDeleteDuplicateStatusTrigger(String triggerName, String tableName) {
final Table table = new Table(tableName);
final SQLDeleteQuery deleteOld = SQLQueryBuilder.deleteFrom(table).where(Expression.and(
Expression.equals(new Column(Statuses.ACCOUNT_ID), new Column(Table.NEW, Statuses.ACCOUNT_ID)),
Expression.equals(new Column(Statuses.STATUS_ID), new Column(Table.NEW, Statuses.STATUS_ID))
)).build();
return SQLQueryBuilder.createTrigger(false, true, triggerName)
.type(Type.BEFORE).event(Event.INSERT).on(table).forEachRow(true)
.actions(deleteOld).build();
}
@ -134,19 +157,6 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
}
}
private SQLCreateViewQuery createDirectMessageConversationEntriesView() {
final SQLCreateViewQuery.Builder qb = SQLQueryBuilder.createView(true,
DirectMessages.ConversationEntries.TABLE_NAME);
qb.as(ConversationsEntryQueryBuilder.build());
return qb.build();
}
private SQLCreateViewQuery createDirectMessagesView() {
final SQLCreateViewQuery.Builder qb = SQLQueryBuilder.createView(true, DirectMessages.TABLE_NAME);
qb.as(DirectMessagesQueryBuilder.build());
return qb.build();
}
private void handleVersionChange(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
final HashMap<String, String> accountsAlias = new HashMap<>();
final HashMap<String, String> filtersAlias = new HashMap<>();
@ -188,6 +198,7 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
safeUpgrade(db, SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true, null);
db.beginTransaction();
createViews(db);
createTriggers(db);
createIndices(db);
db.setTransactionSuccessful();
db.endTransaction();

View File

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ 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, 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="match_parent"
android:divider="?android:dividerVertical"
android:orientation="vertical"
android:showDividers="middle"
tools:context=".activity.DonateActivity">
<TableLayout
android:id="@+id/table_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="@dimen/element_spacing_normal">
<TextView
android:id="@+id/label_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:singleLine="true"
android:text="@string/name"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<EditText
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textPersonName"
android:singleLine="true"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="@dimen/element_spacing_normal">
<TextView
android:id="@+id/label_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:singleLine="true"
android:text="@string/amount_usd"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<EditText
android:id="@+id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="numberDecimal"
android:singleLine="true"/>
</TableRow>
</TableLayout>
<Button
android:id="@+id/donate"
android:layout_width="match_parent"
android:layout_height="@dimen/button_bar_height"
android:layout_weight="0"
android:background="?android:selectableItemBackground"
android:text="@string/donate"/>
</LinearLayout>

View File

@ -529,10 +529,6 @@
<string name="report_user">Report <xliff:g id="name">%s</xliff:g></string>
<string name="report_user_confirm_message">Report <xliff:g id="name">%s</xliff:g> for spam? You\'ll also block this user.</string>
<string name="twidere_test">Twidere test</string>
<string name="donate_via_paypal">Donate via PayPal</string>
<string name="pay_via_paypal">Pay via PayPal directly</string>
<string name="pay_via_paypal_summary">When you see &quot;This recipient is not eligible to receive funds&quot;</string>
<string name="donate_via_alipay">Donate via Alipay</string>
<string name="staggered_home_timeline">Staggered Home Timeline</string>
<string name="unread_count">Unread count</string>
<string name="developed_by">Developed by</string>
@ -740,6 +736,7 @@
<string name="scale">Scale</string>
<string name="user_type_verified">Verified</string>
<string name="user_type_protected">Protected</string>
<string name="donate_summary">See project page</string>
</resources>

View File

@ -31,19 +31,12 @@
<PreferenceCategory
android:key="cat_donate"
android:title="@string/donate">
<Preference android:title="@string/donate_via_paypal">
<Preference android:title="@string/donate"
android:summary="@string/donate_summary">
<intent
android:action="android.intent.action.VIEW"
android:data="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&amp;business=mariotaku.lee%40gmail%2ecom&amp;item_name=Donate%20to%20Twidere"/>
android:data="https://github.com/TwidereProject/Twidere-Android#donation"/>
</Preference>
<Preference
android:fragment="org.mariotaku.twidere.fragment.PayPalDonateFragment"
android:summary="@string/pay_via_paypal_summary"
android:title="@string/pay_via_paypal">
</Preference>
<Preference
android:title="@string/donate_via_alipay"
android:summary="mariotaku.lee@gmail.com"/>
<Preference
android:summary="@string/contributors_list_summary"
android:title="@string/donators">