ログインしたアカウントの識別にメールアドレスを使うのをやめた
|
@ -2,6 +2,7 @@
|
|||
<dictionary name="tateisu">
|
||||
<words>
|
||||
<w>favourited</w>
|
||||
<w>nsfw</w>
|
||||
<w>reblog</w>
|
||||
<w>reblogged</w>
|
||||
<w>reblogs</w>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="AndroidLintSetTextI18n" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
|
||||
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -29,4 +29,9 @@ dependencies {
|
|||
compile 'com.android.support:design:24.2.0'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
testCompile 'junit:junit:4.12'
|
||||
|
||||
compile 'com.github.bumptech.glide:glide:3.7.0'
|
||||
compile 'com.android.volley:volley:1.0.0'
|
||||
compile 'com.android.support:customtabs:24.2.0'
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="jp.juggler.subwaytooter">
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
|
@ -19,13 +18,20 @@
|
|||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ActPost"
|
||||
android:label="@string/act_post"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -3,27 +3,40 @@ package jp.juggler.subwaytooter;
|
|||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.os.AsyncTaskCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.Window;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import jp.juggler.subwaytooter.api.TootApiClient;
|
||||
import jp.juggler.subwaytooter.api.TootApiResult;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.dialog.AccountPicker;
|
||||
import jp.juggler.subwaytooter.dialog.LoginForm;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
|
@ -34,8 +47,28 @@ public class ActMain extends AppCompatActivity
|
|||
@Override
|
||||
protected void onCreate( Bundle savedInstanceState ){
|
||||
super.onCreate( savedInstanceState );
|
||||
initUI();
|
||||
requestWindowFeature( Window.FEATURE_NO_TITLE );
|
||||
|
||||
initUI();
|
||||
loadColumnList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy(){
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume(){
|
||||
super.onResume();
|
||||
HTMLDecoder.link_callback = link_click_listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause(){
|
||||
HTMLDecoder.link_callback = null;
|
||||
saveColumnList();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,20 +112,20 @@ public class ActMain extends AppCompatActivity
|
|||
if( id == R.id.nav_account_add ){
|
||||
performAccountAdd();
|
||||
}else if( id == R.id.nav_add_tl_home ){
|
||||
performAddTimeline(Column.TYPE_TL_HOME );
|
||||
performAddTimeline( Column.TYPE_TL_HOME );
|
||||
}else if( id == R.id.nav_add_tl_local ){
|
||||
performAddTimeline(Column.TYPE_TL_LOCAL );
|
||||
performAddTimeline( Column.TYPE_TL_LOCAL );
|
||||
}else if( id == R.id.nav_add_tl_federate ){
|
||||
performAddTimeline(Column.TYPE_TL_FEDERATE );
|
||||
performAddTimeline( Column.TYPE_TL_FEDERATE );
|
||||
|
||||
}else if( id == R.id.nav_add_favourites ){
|
||||
performAddTimeline(Column.TYPE_TL_FAVOURITES );
|
||||
performAddTimeline( Column.TYPE_TL_FAVOURITES );
|
||||
// }else if( id == R.id.nav_add_reports ){
|
||||
// performAddTimeline(Column.TYPE_TL_REPORTS );
|
||||
}else if( id == R.id.nav_add_statuses ){
|
||||
performAddTimeline(Column.TYPE_TL_STATUSES );
|
||||
performAddTimeline( Column.TYPE_TL_STATUSES );
|
||||
}else if( id == R.id.nav_add_notifications ){
|
||||
performAddTimeline(Column.TYPE_TL_NOTIFICATIONS );
|
||||
performAddTimeline( Column.TYPE_TL_NOTIFICATIONS );
|
||||
|
||||
// Handle the camera action
|
||||
// }else if( id == R.id.nav_gallery ){
|
||||
|
@ -119,28 +152,37 @@ public class ActMain extends AppCompatActivity
|
|||
void initUI(){
|
||||
setContentView( R.layout.act_main );
|
||||
llEmpty = findViewById( R.id.llEmpty );
|
||||
|
||||
// toolbar
|
||||
Toolbar toolbar = (Toolbar) findViewById( R.id.toolbar );
|
||||
setSupportActionBar( toolbar );
|
||||
|
||||
// // toolbar
|
||||
// Toolbar toolbar = (Toolbar) findViewById( R.id.toolbar );
|
||||
// setSupportActionBar( toolbar );
|
||||
|
||||
// navigation drawer
|
||||
DrawerLayout drawer = (DrawerLayout) findViewById( R.id.drawer_layout );
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
||||
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close );
|
||||
drawer.addDrawerListener( toggle );
|
||||
toggle.syncState();
|
||||
final DrawerLayout drawer = (DrawerLayout) findViewById( R.id.drawer_layout );
|
||||
// ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
||||
// this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close );
|
||||
// drawer.addDrawerListener( toggle );
|
||||
// toggle.syncState();
|
||||
|
||||
NavigationView navigationView = (NavigationView) findViewById( R.id.nav_view );
|
||||
navigationView.setNavigationItemSelectedListener( this );
|
||||
|
||||
// floating action button
|
||||
FloatingActionButton fab = (FloatingActionButton) findViewById( R.id.fab );
|
||||
fab.setOnClickListener( new View.OnClickListener() {
|
||||
FloatingActionButton fabToot = (FloatingActionButton) findViewById( R.id.fabToot );
|
||||
fabToot.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View view ){
|
||||
Snackbar.make( view, "Replace with your own action", Snackbar.LENGTH_LONG )
|
||||
.setAction( "Action", null ).show();
|
||||
performTootButton();
|
||||
}
|
||||
} );
|
||||
// floating action button
|
||||
FloatingActionButton fabMenu = (FloatingActionButton) findViewById( R.id.fabMenu );
|
||||
fabMenu.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick( View view ){
|
||||
if( ! drawer.isDrawerOpen( Gravity.LEFT ) ){
|
||||
drawer.openDrawer( Gravity.LEFT );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
|
@ -154,17 +196,17 @@ public class ActMain extends AppCompatActivity
|
|||
LoginForm.showLoginForm( this, new LoginForm.LoginFormCallback() {
|
||||
|
||||
@Override
|
||||
public void startLogin( final Dialog dialog,final String instance, final String user_mail, final String password ){
|
||||
|
||||
public void startLogin( final Dialog dialog, final String instance, final String user_mail, final String password ){
|
||||
|
||||
final ProgressDialog progress = new ProgressDialog( ActMain.this );
|
||||
|
||||
|
||||
final AsyncTask< Void, String, TootApiResult > task = new AsyncTask< Void, String, TootApiResult >() {
|
||||
|
||||
|
||||
boolean __isCancelled(){
|
||||
return isCancelled();
|
||||
}
|
||||
|
||||
boolean is_added = false;
|
||||
long row_id;
|
||||
|
||||
@Override
|
||||
protected TootApiResult doInBackground( Void... params ){
|
||||
|
@ -189,8 +231,9 @@ public class ActMain extends AppCompatActivity
|
|||
|
||||
TootApiResult result = api_client.get( "/api/v1/accounts/verify_credentials" );
|
||||
if( result != null && result.object != null ){
|
||||
is_added = ! SavedAccount.hasAccount(log,instance, user_mail);
|
||||
SavedAccount.save( log,instance, user_mail, result.object );
|
||||
TootAccount ta = TootAccount.parse( log, result.object );
|
||||
String user = ta.username +"@" + instance;
|
||||
this.row_id = SavedAccount.insert( log, instance, user, result.object ,result.token_info );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -198,16 +241,16 @@ public class ActMain extends AppCompatActivity
|
|||
@Override
|
||||
protected void onPostExecute( TootApiResult result ){
|
||||
progress.dismiss();
|
||||
|
||||
|
||||
if( result == null ){
|
||||
// cancelled.
|
||||
}else if( result.object == null ){
|
||||
Utils.showToast( ActMain.this, true, result.error );
|
||||
log.e( result.error );
|
||||
}else{
|
||||
SavedAccount account = SavedAccount.loadAccount(log,instance,user_mail);
|
||||
SavedAccount account = SavedAccount.loadAccount( log, row_id );
|
||||
if( account != null ){
|
||||
ActMain.this.onAccountUpdated(account,is_added);
|
||||
ActMain.this.onAccountUpdated( account );
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
@ -228,32 +271,130 @@ public class ActMain extends AppCompatActivity
|
|||
|
||||
}
|
||||
|
||||
private void onAccountUpdated( SavedAccount data ){
|
||||
Utils.showToast( this, false, R.string.account_confirmed );
|
||||
//
|
||||
llEmpty.setVisibility( View.GONE );
|
||||
//
|
||||
Column col = new Column( this, data, Column.TYPE_TL_HOME );
|
||||
int idx = pager_adapter.addColumn( pager, col );
|
||||
pager.setCurrentItem( idx );
|
||||
}
|
||||
|
||||
public void performColumnClose( Column column ){
|
||||
pager_adapter.removeColumn( pager,column );
|
||||
pager_adapter.removeColumn( pager, column );
|
||||
if( pager_adapter.getCount() == 0 ){
|
||||
llEmpty.setVisibility( View.VISIBLE );
|
||||
}
|
||||
}
|
||||
|
||||
private void onAccountUpdated( SavedAccount data, boolean is_added){
|
||||
Utils.showToast(this,false,R.string.accout_confirmed);
|
||||
if( is_added ){
|
||||
Column col = new Column( this, data, Column.TYPE_TL_HOME );
|
||||
pager_adapter.addColumn( pager, col );
|
||||
private void performAddTimeline( final int type, final Object... params ){
|
||||
AccountPicker.pick( this, new AccountPicker.AccountPickerCallback() {
|
||||
@Override
|
||||
public void onAccountPicked( SavedAccount ai ){
|
||||
llEmpty.setVisibility( View.GONE );
|
||||
//
|
||||
Column col = new Column( ActMain.this, ai, type, ai.id, params );
|
||||
int idx = pager_adapter.addColumn( pager, col );
|
||||
pager.setCurrentItem( idx );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void openBrowser( String url ){
|
||||
openChromeTab( url );
|
||||
}
|
||||
|
||||
public void openChromeTab( String url ){
|
||||
try{
|
||||
// ビルダーを使って表示方法を指定する
|
||||
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
||||
builder.setToolbarColor( ContextCompat.getColor( this, R.color.colorPrimary ) ).setShowTitle( true );
|
||||
|
||||
// CustomTabsでURLをひらくIntentを発行
|
||||
CustomTabsIntent customTabsIntent = builder.build();
|
||||
customTabsIntent.launchUrl( this, Uri.parse( url ) );
|
||||
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
log.e( ex, "openChromeTab failed." );
|
||||
}
|
||||
}
|
||||
|
||||
final HTMLDecoder.LinkClickCallback link_click_listener = new HTMLDecoder.LinkClickCallback() {
|
||||
@Override
|
||||
public void onClickLink( String url ){
|
||||
openChromeTab( url );
|
||||
}
|
||||
};
|
||||
|
||||
static final String FILE_COLUMN_LIST = "column_list";
|
||||
|
||||
private void loadColumnList(){
|
||||
try{
|
||||
InputStream is = openFileInput( FILE_COLUMN_LIST );
|
||||
try{
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream( is.available() );
|
||||
byte[] tmp = new byte[ 4096 ];
|
||||
for( ; ; ){
|
||||
int r = is.read( tmp, 0, tmp.length );
|
||||
if( r <= 0 ) break;
|
||||
bao.write( tmp, 0, r );
|
||||
}
|
||||
JSONArray array = new JSONArray( Utils.decodeUTF8( bao.toByteArray() ) );
|
||||
for( int i = 0, ie = array.length() ; i < ie ; ++ i ){
|
||||
try{
|
||||
JSONObject src = array.optJSONObject( i );
|
||||
Column col = new Column( ActMain.this, src );
|
||||
pager_adapter.addColumn( pager, col );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}finally{
|
||||
is.close();
|
||||
}
|
||||
}catch( FileNotFoundException ignored ){
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
Utils.showToast( this, ex, "loadColumnList failed." );
|
||||
}
|
||||
|
||||
if( pager_adapter.column_list.size() > 0 ){
|
||||
llEmpty.setVisibility( View.GONE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void performAddTimeline( final int type,final Object... params){
|
||||
AccountPicker.pick( this, new AccountPicker.AccountPickerCallback() {
|
||||
@Override
|
||||
public void onAccountPicked( SavedAccount ai ){
|
||||
Column col = new Column( ActMain.this, ai, type ,ai.id,params);
|
||||
pager_adapter.addColumn( pager, col );
|
||||
pager.setCurrentItem( pager_adapter.getCount() -1 );
|
||||
llEmpty.setVisibility( View.GONE );
|
||||
private void saveColumnList(){
|
||||
JSONArray array = new JSONArray();
|
||||
for( Column column : pager_adapter.column_list ){
|
||||
try{
|
||||
JSONObject item = new JSONObject();
|
||||
column.encodeJSON( item );
|
||||
array.put( item );
|
||||
}catch( JSONException ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
} );
|
||||
}
|
||||
try{
|
||||
OutputStream os = openFileOutput( FILE_COLUMN_LIST, MODE_PRIVATE );
|
||||
try{
|
||||
os.write( Utils.encodeUTF8( array.toString() ) );
|
||||
}finally{
|
||||
os.close();
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
Utils.showToast( this, ex, "saveColumnList failed." );
|
||||
}
|
||||
}
|
||||
|
||||
private void performTootButton(){
|
||||
|
||||
Column c = pager_adapter.getColumn( pager.getCurrentItem() );
|
||||
if( c != null && c.access_info != null ){
|
||||
ActPost.open( this, c.access_info.db_id );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
package jp.juggler.subwaytooter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.volley.toolbox.NetworkImageView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||
static final LogCategory log = new LogCategory( "ActPost" );
|
||||
|
||||
static final String KEY_ACCOUNT_DB_ID = "account_db_id";
|
||||
|
||||
public static void open( Context context, long account_db_id ){
|
||||
Intent intent = new Intent( context, ActPost.class );
|
||||
intent.putExtra( KEY_ACCOUNT_DB_ID, account_db_id );
|
||||
context.startActivity( intent );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick( View v ){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate( @Nullable Bundle savedInstanceState ){
|
||||
super.onCreate( savedInstanceState );
|
||||
|
||||
initUI();
|
||||
|
||||
if( account_list.isEmpty() ){
|
||||
Utils.showToast( this, true, R.string.please_add_account );
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if( savedInstanceState != null ){
|
||||
|
||||
}else{
|
||||
Intent intent = getIntent();
|
||||
long account_db_id = intent.getLongExtra( KEY_ACCOUNT_DB_ID, SavedAccount.INVALID_ID );
|
||||
if( account_db_id != SavedAccount.INVALID_ID ){
|
||||
for( int i = 0, ie = account_list.size() ; i < ie ; ++ i ){
|
||||
SavedAccount a = account_list.get( i );
|
||||
if( a.db_id == account_db_id ){
|
||||
setAccount( a );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( this.account == null ){
|
||||
setAccount( null );
|
||||
}
|
||||
|
||||
updateContentWarning();
|
||||
updateMediaAttachment();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState( Bundle savedInstanceState ){
|
||||
super.onRestoreInstanceState( savedInstanceState );
|
||||
|
||||
if( savedInstanceState != null ){
|
||||
long account_db_id = savedInstanceState.getLong(KEY_ACCOUNT_DB_ID,SavedAccount.INVALID_ID);
|
||||
if( account_db_id != SavedAccount.INVALID_ID ){
|
||||
for( int i = 0, ie = account_list.size() ; i < ie ; ++ i ){
|
||||
SavedAccount a = account_list.get( i );
|
||||
if( a.db_id == account_db_id ){
|
||||
setAccount( a );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if( this.account == null ){
|
||||
setAccount( null );
|
||||
}
|
||||
updateContentWarning();
|
||||
updateMediaAttachment();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState( Bundle outState ){
|
||||
if( account != null ){
|
||||
outState.putLong( KEY_ACCOUNT_DB_ID,account.db_id );
|
||||
}
|
||||
}
|
||||
|
||||
Button btnAccount;
|
||||
View btnAttachment;
|
||||
View btnPost;
|
||||
View llAttachment;
|
||||
NetworkImageView ivMedia1;
|
||||
NetworkImageView ivMedia2;
|
||||
NetworkImageView ivMedia3;
|
||||
NetworkImageView ivMedia4;
|
||||
CheckBox cbContentWarning;
|
||||
EditText etContentWarning;
|
||||
EditText etContent;
|
||||
TextView tvCharCount;
|
||||
ArrayList< SavedAccount > account_list;
|
||||
SavedAccount account;
|
||||
|
||||
private void initUI(){
|
||||
setContentView( R.layout.act_post );
|
||||
|
||||
btnAccount = (Button) findViewById( R.id.btnAccount );
|
||||
btnAttachment = findViewById( R.id.btnAttachment );
|
||||
btnPost = findViewById( R.id.btnPost );
|
||||
llAttachment = findViewById( R.id.llAttachment );
|
||||
ivMedia1 = (NetworkImageView) findViewById( R.id.ivMedia1 );
|
||||
ivMedia2 = (NetworkImageView) findViewById( R.id.ivMedia2 );
|
||||
ivMedia3 = (NetworkImageView) findViewById( R.id.ivMedia3 );
|
||||
ivMedia4 = (NetworkImageView) findViewById( R.id.ivMedia4 );
|
||||
cbContentWarning = (CheckBox) findViewById( R.id.cbContentWarning );
|
||||
etContentWarning = (EditText) findViewById( R.id.etContentWarning );
|
||||
etContent = (EditText) findViewById( R.id.etContent );
|
||||
tvCharCount = (TextView) findViewById( R.id.tvCharCount );
|
||||
|
||||
account_list = SavedAccount.loadAccountList( log );
|
||||
Collections.sort( account_list, new Comparator< SavedAccount >() {
|
||||
@Override
|
||||
public int compare( SavedAccount a, SavedAccount b ){
|
||||
return String.CASE_INSENSITIVE_ORDER.compare( a.getFullAcct( a ), b.getFullAcct( b ) );
|
||||
}
|
||||
} );
|
||||
|
||||
btnAccount.setOnClickListener( this );
|
||||
btnAttachment.setOnClickListener( this );
|
||||
btnPost.setOnClickListener( this );
|
||||
llAttachment = findViewById( R.id.llAttachment );
|
||||
ivMedia1.setOnClickListener( this );
|
||||
ivMedia2.setOnClickListener( this );
|
||||
ivMedia3.setOnClickListener( this );
|
||||
ivMedia4.setOnClickListener( this );
|
||||
cbContentWarning.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged( CompoundButton buttonView, boolean isChecked ){
|
||||
updateContentWarning();
|
||||
}
|
||||
} );
|
||||
|
||||
etContent.addTextChangedListener( new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged( CharSequence s, int start, int count, int after ){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged( CharSequence s, int start, int before, int count ){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged( Editable s ){
|
||||
updateTextCount();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private void updateTextCount(){
|
||||
tvCharCount.setText( 500 - etContent.getText().length() );
|
||||
}
|
||||
|
||||
void setAccount( SavedAccount a ){
|
||||
this.account = a;
|
||||
btnAccount.setText( a == null ? getString( R.string.not_selected ) : a.getFullAcct( a ) );
|
||||
}
|
||||
|
||||
private void updateContentWarning(){
|
||||
etContentWarning.setVisibility( cbContentWarning.isChecked() ? View.VISIBLE : View.GONE );
|
||||
}
|
||||
|
||||
private void updateMediaAttachment(){
|
||||
if( attachment_list.isEmpty() ){
|
||||
llAttachment.setVisibility( View.GONE );
|
||||
}else{
|
||||
llAttachment.setVisibility( View.VISIBLE );
|
||||
showAttachment( ivMedia1, 0 );
|
||||
showAttachment( ivMedia2, 0 );
|
||||
showAttachment( ivMedia3, 0 );
|
||||
showAttachment( ivMedia4, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
private void showAttachment( NetworkImageView iv, int idx ){
|
||||
if( idx >= attachment_list.size() ){
|
||||
iv.setVisibility( View.GONE );
|
||||
}else{
|
||||
iv.setVisibility( View.VISIBLE );
|
||||
PostAttachment a = attachment_list.get( idx );
|
||||
if( a.status == ATTACHMENT_UPLOADING ){
|
||||
iv.setImageResource( R.drawable.ic_loading );
|
||||
}else{
|
||||
iv.setImageBitmap( a.bitmap );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final int ATTACHMENT_UPLOADING = 1;
|
||||
static final int ATTACHMENT_UPLOADED = 2;
|
||||
|
||||
static class PostAttachment {
|
||||
int status;
|
||||
Bitmap bitmap;
|
||||
String url;
|
||||
}
|
||||
|
||||
final ArrayList< PostAttachment > attachment_list = new ArrayList<>();
|
||||
|
||||
}
|
|
@ -4,19 +4,36 @@ import android.app.Application;
|
|||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.v4.util.LruCache;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.android.volley.DefaultRetryPolicy;
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.toolbox.ImageLoader;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
|
||||
import jp.juggler.subwaytooter.table.AccessToken;
|
||||
import jp.juggler.subwaytooter.table.ClientInfo;
|
||||
import jp.juggler.subwaytooter.table.ContentWarning;
|
||||
import jp.juggler.subwaytooter.table.LogData;
|
||||
import jp.juggler.subwaytooter.table.MediaShown;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
|
||||
public class App1 extends Application{
|
||||
public class App1 extends Application {
|
||||
|
||||
@Override
|
||||
public void onCreate(){
|
||||
super.onCreate();
|
||||
if( db_open_helper == null ){
|
||||
db_open_helper = new DBOpenHelper( getApplicationContext() );
|
||||
db_open_helper.onCreate( getDB() );
|
||||
}
|
||||
if( image_loader == null ){
|
||||
image_loader = new MyImageLoader(
|
||||
Volley.newRequestQueue( getApplicationContext() )
|
||||
, new BitmapCache()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,10 +42,9 @@ public class App1 extends Application{
|
|||
super.onTerminate();
|
||||
}
|
||||
|
||||
|
||||
static final String DB_NAME = "app_db";
|
||||
static final int DB_VERSION = 1;
|
||||
|
||||
|
||||
static DBOpenHelper db_open_helper;
|
||||
|
||||
public static SQLiteDatabase getDB(){
|
||||
|
@ -38,24 +54,84 @@ public class App1 extends Application{
|
|||
static class DBOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
public DBOpenHelper( Context context ){
|
||||
super( context, DB_NAME, null , DB_VERSION );
|
||||
super( context, DB_NAME, null, DB_VERSION );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate( SQLiteDatabase db ){
|
||||
LogData.onDBCreate( db);
|
||||
LogData.onDBCreate( db );
|
||||
//
|
||||
AccessToken.onDBCreate(db);
|
||||
SavedAccount.onDBCreate(db);
|
||||
ClientInfo.onDBCreate( db);
|
||||
SavedAccount.onDBCreate( db );
|
||||
ClientInfo.onDBCreate( db );
|
||||
MediaShown.onDBCreate(db);
|
||||
ContentWarning.onDBCreate(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
|
||||
LogData.onDBUpgrade( db,oldVersion,newVersion );
|
||||
AccessToken.onDBUpgrade( db,oldVersion,newVersion );
|
||||
SavedAccount.onDBUpgrade( db,oldVersion,newVersion );
|
||||
ClientInfo.onDBUpgrade( db,oldVersion,newVersion );
|
||||
LogData.onDBUpgrade( db, oldVersion, newVersion );
|
||||
//
|
||||
SavedAccount.onDBUpgrade( db, oldVersion, newVersion );
|
||||
ClientInfo.onDBUpgrade( db, oldVersion, newVersion );
|
||||
MediaShown.onDBUpgrade( db, oldVersion, newVersion );
|
||||
ContentWarning.onDBUpgrade( db, oldVersion, newVersion );
|
||||
}
|
||||
}
|
||||
|
||||
static ImageLoader image_loader;
|
||||
|
||||
public static ImageLoader getImageLoader(){
|
||||
return image_loader;
|
||||
}
|
||||
|
||||
public static class MyImageLoader extends ImageLoader {
|
||||
|
||||
/**
|
||||
* Constructs a new ImageLoader.
|
||||
*
|
||||
* @param queue The RequestQueue to use for making image requests.
|
||||
* @param imageCache The cache to use as an L1 cache.
|
||||
*/
|
||||
public MyImageLoader( RequestQueue queue, ImageCache imageCache ){
|
||||
super( queue, imageCache );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Request< Bitmap > makeImageRequest( String requestUrl, int maxWidth, int maxHeight, ImageView.ScaleType scaleType, String cacheKey ){
|
||||
Request< Bitmap > req = super.makeImageRequest( requestUrl, maxWidth, maxHeight, scaleType, cacheKey );
|
||||
req.setRetryPolicy(new DefaultRetryPolicy(
|
||||
30000 // SOCKET_TIMEOUT_MS
|
||||
,3 // DefaultRetryPolicy.DEFAULT_MAX_RETRIES
|
||||
,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
|
||||
));
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BitmapCache implements ImageLoader.ImageCache {
|
||||
|
||||
private LruCache<String, Bitmap> mCache;
|
||||
|
||||
public BitmapCache() {
|
||||
int maxSize = 10 * 1024 * 1024;
|
||||
mCache = new LruCache<String, Bitmap>(maxSize) {
|
||||
@Override
|
||||
protected int sizeOf(String key, Bitmap value) {
|
||||
return value.getRowBytes() * value.getHeight();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap(String url) {
|
||||
return mCache.get(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBitmap(String url, Bitmap bitmap) {
|
||||
mCache.put(url, bitmap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package jp.juggler.subwaytooter;
|
|||
import android.os.AsyncTask;
|
||||
import android.support.v4.os.AsyncTaskCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
@ -21,6 +23,10 @@ import jp.juggler.subwaytooter.util.Utils;
|
|||
public class Column {
|
||||
static final LogCategory log = new LogCategory( "Column" );
|
||||
|
||||
static final String KEY_ACCOUNT_ROW_ID = "account_id";
|
||||
static final String KEY_TYPE = "type";
|
||||
static final String KEY_WHO_ID = "who_id";
|
||||
|
||||
final ActMain activity;
|
||||
final SavedAccount access_info;
|
||||
final int type;
|
||||
|
@ -35,10 +41,10 @@ public class Column {
|
|||
static final int TYPE_TL_NOTIFICATIONS = 7;
|
||||
|
||||
public Column( ActMain activity, SavedAccount access_info, int type ){
|
||||
this( activity,access_info,type,access_info.id);
|
||||
this( activity, access_info, type, access_info.id );
|
||||
}
|
||||
|
||||
public Column( ActMain activity, SavedAccount access_info, int type ,long who_id,Object... params){
|
||||
public Column( ActMain activity, SavedAccount access_info, int type, long who_id, Object... params ){
|
||||
this.activity = activity;
|
||||
this.access_info = access_info;
|
||||
this.type = type;
|
||||
|
@ -46,36 +52,51 @@ public class Column {
|
|||
startLoading();
|
||||
}
|
||||
|
||||
public Column( ActMain activity, JSONObject src ){
|
||||
this.activity = activity;
|
||||
this.access_info = SavedAccount.loadAccount( log, src.optLong( KEY_ACCOUNT_ROW_ID ) );
|
||||
if( access_info == null ) throw new RuntimeException( "missing account" );
|
||||
this.type = src.optInt( KEY_TYPE );
|
||||
this.who_id = src.optLong( KEY_WHO_ID );
|
||||
startLoading();
|
||||
}
|
||||
|
||||
final AtomicBoolean is_dispose = new AtomicBoolean();
|
||||
|
||||
void dispose(){
|
||||
is_dispose.set( true );
|
||||
}
|
||||
|
||||
public void encodeJSON( JSONObject item ) throws JSONException{
|
||||
item.put( KEY_ACCOUNT_ROW_ID , access_info.db_id );
|
||||
item.put( KEY_TYPE, type );
|
||||
item.put( KEY_WHO_ID, who_id );
|
||||
}
|
||||
|
||||
public String getColumnName(){
|
||||
switch( type ){
|
||||
default:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + "?";
|
||||
return "?";
|
||||
case TYPE_TL_HOME:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + activity.getString( R.string.home );
|
||||
return activity.getString( R.string.home );
|
||||
case TYPE_TL_LOCAL:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + activity.getString( R.string.local_timeline );
|
||||
return activity.getString( R.string.local_timeline );
|
||||
case TYPE_TL_FEDERATE:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + activity.getString( R.string.federate_timeline );
|
||||
return activity.getString( R.string.federate_timeline );
|
||||
|
||||
case TYPE_TL_STATUSES:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + activity.getString( R.string.statuses_of
|
||||
return activity.getString( R.string.statuses_of
|
||||
, who_account != null ? access_info.getFullAcct( who_account ) : Long.toString( who_id )
|
||||
);
|
||||
|
||||
case TYPE_TL_FAVOURITES:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + activity.getString( R.string.favourites );
|
||||
return activity.getString( R.string.favourites );
|
||||
|
||||
case TYPE_TL_REPORTS:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + activity.getString( R.string.reports );
|
||||
return activity.getString( R.string.reports );
|
||||
|
||||
case TYPE_TL_NOTIFICATIONS:
|
||||
return access_info.getFullAcct( access_info ) + "\n" + activity.getString( R.string.notifications );
|
||||
return activity.getString( R.string.notifications );
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +217,7 @@ public class Column {
|
|||
}
|
||||
} );
|
||||
|
||||
client.setAccessInfo( access_info );
|
||||
client.setAccount( access_info );
|
||||
|
||||
switch( type ){
|
||||
default:
|
||||
|
@ -215,7 +236,7 @@ public class Column {
|
|||
client.callback.publishProgress( "" );
|
||||
}
|
||||
|
||||
return parseStatuses( client.get( "/api/v1/accounts/"+who_id+"/statuses" ) );
|
||||
return parseStatuses( client.get( "/api/v1/accounts/" + who_id + "/statuses" ) );
|
||||
|
||||
case TYPE_TL_FAVOURITES:
|
||||
return parseStatuses( client.get( "/api/v1/favourites" ) );
|
||||
|
|
|
@ -28,18 +28,11 @@ public class ColumnPagerAdapter extends PagerAdapter{
|
|||
|
||||
int addColumn( ViewPager pager, Column column ){
|
||||
int size = column_list.size();
|
||||
if( size == 0 ){
|
||||
column_list.add( column );
|
||||
notifyDataSetChanged();
|
||||
return 0;
|
||||
}else{
|
||||
int idx = 1+pager.getCurrentItem();
|
||||
column_list.add( idx, column );
|
||||
notifyDataSetChanged();
|
||||
pager.setCurrentItem( idx );
|
||||
return idx;
|
||||
}
|
||||
column_list.add( column );
|
||||
notifyDataSetChanged();
|
||||
return size;
|
||||
}
|
||||
|
||||
public void removeColumn( ViewPager pager,Column column ){
|
||||
int idx_column = column_list.indexOf( column );
|
||||
if( idx_column == - 1 ) return;
|
||||
|
@ -53,7 +46,8 @@ public class ColumnPagerAdapter extends PagerAdapter{
|
|||
|
||||
|
||||
public Column getColumn( int idx ){
|
||||
return column_list.get( idx );
|
||||
if( idx >= 0 && idx < column_list.size() ) return column_list.get( idx );
|
||||
return null;
|
||||
}
|
||||
|
||||
public ColumnViewHolder getColumnViewHolder( int idx ){
|
||||
|
|
|
@ -1,22 +1,34 @@
|
|||
package jp.juggler.subwaytooter;
|
||||
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.volley.toolbox.NetworkImageView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAttachment;
|
||||
import jp.juggler.subwaytooter.api.entity.TootNotification;
|
||||
import jp.juggler.subwaytooter.api.entity.TootReport;
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||
import jp.juggler.subwaytooter.table.ContentWarning;
|
||||
import jp.juggler.subwaytooter.table.MediaShown;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
public class ColumnViewHolder implements View.OnClickListener, Column.VisualCallback {
|
||||
static final LogCategory log = new LogCategory( "ColumnViewHolder" );
|
||||
|
@ -27,7 +39,7 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
public final int column_index;
|
||||
|
||||
public ColumnViewHolder( ActMain activity, Column column, int column_index ){
|
||||
log.d("ctor");
|
||||
log.d( "ctor" );
|
||||
this.activity = activity;
|
||||
this.column = column;
|
||||
this.column_index = column_index;
|
||||
|
@ -39,15 +51,17 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
|
||||
TextView tvLoading;
|
||||
ListView listView;
|
||||
TextView tvColumnContext;
|
||||
TextView tvColumnName;
|
||||
StatusListAdapter status_adapter;
|
||||
HeaderViewHolder vh_header;
|
||||
|
||||
void onPageCreate( View root ){
|
||||
log.d("onPageCreate:%s",column.getColumnName() );
|
||||
log.d( "onPageCreate:%s", column.getColumnName() );
|
||||
|
||||
tvColumnName = (TextView) root.findViewById( R.id.tvColumnName );
|
||||
tvColumnName = (TextView) root.findViewById( R.id.tvColumnName );
|
||||
tvColumnContext = (TextView) root.findViewById( R.id.tvColumnContext );
|
||||
|
||||
|
||||
root.findViewById( R.id.btnColumnClose ).setOnClickListener( this );
|
||||
root.findViewById( R.id.btnColumnReload ).setOnClickListener( this );
|
||||
|
||||
|
@ -55,17 +69,23 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
listView = (ListView) root.findViewById( R.id.listView );
|
||||
status_adapter = new StatusListAdapter();
|
||||
listView.setAdapter( status_adapter );
|
||||
|
||||
if( column.type == Column.TYPE_TL_STATUSES ){
|
||||
vh_header = new HeaderViewHolder( activity, listView );
|
||||
listView.addHeaderView( vh_header.viewRoot );
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
||||
column.addVisualListener( this );
|
||||
onVisualColumn();
|
||||
}
|
||||
|
||||
void onPageDestroy( View root ){
|
||||
log.d("onPageDestroy:%s",column.getColumnName() );
|
||||
log.d( "onPageDestroy:%s", column.getColumnName() );
|
||||
column.removeVisualListener( this );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick( View v ){
|
||||
switch( v.getId() ){
|
||||
|
@ -79,34 +99,34 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
|
||||
}
|
||||
|
||||
void showError(String message){
|
||||
tvLoading.setVisibility( View.VISIBLE );
|
||||
listView.setVisibility( View.GONE );
|
||||
tvLoading.setText( message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVisualColumn(){
|
||||
|
||||
tvColumnName.setText(column.getColumnName() );
|
||||
|
||||
tvColumnContext.setText( column.access_info.getFullAcct( column.access_info ) );
|
||||
tvColumnName.setText( column.getColumnName() );
|
||||
|
||||
if( column.is_dispose.get() ){
|
||||
tvLoading.setVisibility( View.VISIBLE );
|
||||
listView.setVisibility( View.GONE );
|
||||
tvLoading.setText( "column was disposed." );
|
||||
showError("column was disposed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if( vh_header != null ){
|
||||
vh_header.bind( activity, column.access_info, column.who_account );
|
||||
}
|
||||
|
||||
if( column.is_loading ){
|
||||
tvLoading.setVisibility( View.VISIBLE );
|
||||
listView.setVisibility( View.GONE );
|
||||
String progress = column.task_progress;
|
||||
if( progress == null ) progress = "loading?";
|
||||
tvLoading.setText( progress );
|
||||
String message = column.task_progress;
|
||||
if( message == null ) message = "loading?";
|
||||
showError( message);
|
||||
return;
|
||||
}
|
||||
tvLoading.setVisibility( View.GONE );
|
||||
|
||||
if( column.who_account != null ){
|
||||
// TODO
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
|
||||
switch( column.type ){
|
||||
default:
|
||||
case Column.TYPE_TL_HOME:
|
||||
|
@ -114,16 +134,31 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
case Column.TYPE_TL_FEDERATE:
|
||||
case Column.TYPE_TL_FAVOURITES:
|
||||
case Column.TYPE_TL_STATUSES:
|
||||
listView.setVisibility( View.VISIBLE );
|
||||
status_adapter.set( column.status_list );
|
||||
if( column.status_list.isEmpty() && vh_header == null ){
|
||||
showError(activity.getString(R.string.list_empty));
|
||||
}else{
|
||||
tvLoading.setVisibility( View.GONE );
|
||||
listView.setVisibility( View.VISIBLE );
|
||||
status_adapter.set( column.status_list );
|
||||
}
|
||||
break;
|
||||
case Column.TYPE_TL_REPORTS:
|
||||
listView.setVisibility( View.VISIBLE );
|
||||
status_adapter.set( column.report_list );
|
||||
if( column.report_list.isEmpty() ){
|
||||
showError(activity.getString(R.string.list_empty));
|
||||
}else{
|
||||
tvLoading.setVisibility( View.GONE );
|
||||
listView.setVisibility( View.VISIBLE );
|
||||
status_adapter.set( column.report_list );
|
||||
}
|
||||
break;
|
||||
case Column.TYPE_TL_NOTIFICATIONS:
|
||||
listView.setVisibility( View.VISIBLE );
|
||||
status_adapter.set( column.notification_list );
|
||||
if( column.notification_list.isEmpty() ){
|
||||
showError(activity.getString(R.string.list_empty));
|
||||
}else{
|
||||
tvLoading.setVisibility( View.GONE );
|
||||
listView.setVisibility( View.VISIBLE );
|
||||
status_adapter.set( column.notification_list );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +168,6 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
class StatusListAdapter extends BaseAdapter {
|
||||
final ArrayList< Object > status_list = new ArrayList<>();
|
||||
|
||||
|
||||
public void set( TootStatus.List src ){
|
||||
this.status_list.clear();
|
||||
this.status_list.addAll( src );
|
||||
|
@ -171,7 +205,7 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
@Override
|
||||
public View getView( int position, View view, ViewGroup parent ){
|
||||
Object o = ( position >= 0 && position < status_list.size() ? status_list.get( position ) : null );
|
||||
|
||||
|
||||
StatusViewHolder holder;
|
||||
if( view == null ){
|
||||
view = activity.getLayoutInflater().inflate( R.layout.lv_status, parent, false );
|
||||
|
@ -186,7 +220,7 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
|
||||
}
|
||||
|
||||
static class StatusViewHolder {
|
||||
class StatusViewHolder implements View.OnClickListener {
|
||||
|
||||
final View llBoosted;
|
||||
final ImageView ivBoosted;
|
||||
|
@ -194,57 +228,89 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
final TextView tvBoostedTime;
|
||||
|
||||
final View llFollow;
|
||||
final ImageView ivFollow;
|
||||
final NetworkImageView ivFollow;
|
||||
final TextView tvFollowerName;
|
||||
final TextView tvFollowerAcct;
|
||||
|
||||
final View llStatus;
|
||||
final ImageView ivThumbnail;
|
||||
final NetworkImageView ivThumbnail;
|
||||
final TextView tvName;
|
||||
final TextView tvTime;
|
||||
|
||||
final View llContentWarning;
|
||||
final TextView tvContentWarning;
|
||||
final Button btnContentWarning;
|
||||
final TextView tvContent;
|
||||
final ImageView ivMedia;
|
||||
|
||||
|
||||
final View flMedia;
|
||||
final View btnHideMedia;
|
||||
final View btnShowMedia;
|
||||
|
||||
final NetworkImageView ivMedia1;
|
||||
final NetworkImageView ivMedia2;
|
||||
final NetworkImageView ivMedia3;
|
||||
final NetworkImageView ivMedia4;
|
||||
|
||||
final ImageButton btnReply;
|
||||
final ImageButton btnBoost;
|
||||
final ImageButton btnFavourite;
|
||||
final Button btnBoost;
|
||||
final Button btnFavourite;
|
||||
final ImageButton btnMore;
|
||||
|
||||
Object item;
|
||||
TootStatus status;
|
||||
SavedAccount account;
|
||||
|
||||
public StatusViewHolder( View view ){
|
||||
this.llBoosted = view.findViewById( R.id.llBoosted );
|
||||
this.llBoosted = view.findViewById( R.id.llBoosted );
|
||||
this.ivBoosted = (ImageView) view.findViewById( R.id.ivBoosted );
|
||||
this.tvBoosted = (TextView) view.findViewById( R.id.tvBoosted );
|
||||
this.tvBoostedTime = (TextView) view.findViewById( R.id.tvBoostedTime );
|
||||
|
||||
this.llFollow = view.findViewById( R.id.llFollow );
|
||||
this.ivFollow = (ImageView) view.findViewById( R.id.ivFollow );
|
||||
this.llFollow = view.findViewById( R.id.llFollow );
|
||||
this.ivFollow = (NetworkImageView) view.findViewById( R.id.ivFollow );
|
||||
this.tvFollowerName = (TextView) view.findViewById( R.id.tvFollowerName );
|
||||
this.tvFollowerAcct = (TextView) view.findViewById( R.id.tvFollowerAcct );
|
||||
|
||||
this.llStatus = view.findViewById( R.id.llStatus );
|
||||
|
||||
this.ivThumbnail = (ImageView) view.findViewById( R.id.ivThumbnail );
|
||||
this.llStatus = view.findViewById( R.id.llStatus );
|
||||
|
||||
this.ivThumbnail = (NetworkImageView) view.findViewById( R.id.ivThumbnail );
|
||||
this.tvName = (TextView) view.findViewById( R.id.tvName );
|
||||
this.tvTime = (TextView) view.findViewById( R.id.tvTime );
|
||||
|
||||
this.llContentWarning = view.findViewById( R.id.llContentWarning );
|
||||
this.tvContentWarning = (TextView) view.findViewById( R.id.tvContentWarning );
|
||||
this.btnContentWarning = (Button) view.findViewById( R.id.btnContentWarning );
|
||||
this.tvContent = (TextView) view.findViewById( R.id.tvContent );
|
||||
this.ivMedia = (ImageView) view.findViewById( R.id.ivMedia );
|
||||
this.btnReply = (ImageButton) view.findViewById( R.id.btnReply );
|
||||
this.btnBoost = (ImageButton) view.findViewById( R.id.btnBoost );
|
||||
this.btnFavourite = (ImageButton) view.findViewById( R.id.btnFavourite );
|
||||
this.btnBoost = (Button) view.findViewById( R.id.btnBoost );
|
||||
this.btnFavourite = (Button) view.findViewById( R.id.btnFavourite );
|
||||
this.btnMore = (ImageButton) view.findViewById( R.id.btnMore );
|
||||
|
||||
this.flMedia = view.findViewById( R.id.flMedia );
|
||||
this.btnHideMedia = view.findViewById( R.id.btnHideMedia );
|
||||
this.btnShowMedia = view.findViewById( R.id.btnShowMedia );
|
||||
this.ivMedia1 = (NetworkImageView) view.findViewById( R.id.ivMedia1 );
|
||||
this.ivMedia2 = (NetworkImageView) view.findViewById( R.id.ivMedia2 );
|
||||
this.ivMedia3 = (NetworkImageView) view.findViewById( R.id.ivMedia3 );
|
||||
this.ivMedia4 = (NetworkImageView) view.findViewById( R.id.ivMedia4 );
|
||||
|
||||
btnContentWarning.setOnClickListener( this );
|
||||
btnHideMedia.setOnClickListener( this );
|
||||
btnShowMedia.setOnClickListener( this );
|
||||
ivMedia1.setOnClickListener( this );
|
||||
ivMedia2.setOnClickListener( this );
|
||||
ivMedia3.setOnClickListener( this );
|
||||
ivMedia4.setOnClickListener( this );
|
||||
|
||||
tvContent.setMovementMethod( LinkMovementMethod.getInstance() );
|
||||
}
|
||||
|
||||
public void bind( ActMain activity, View view, Object item, SavedAccount account ){
|
||||
this.account = account;
|
||||
this.item = item;
|
||||
|
||||
llBoosted.setVisibility( View.GONE );
|
||||
llFollow.setVisibility( View.GONE );
|
||||
llStatus.setVisibility( View.GONE );
|
||||
|
||||
|
||||
if( item == null ) return;
|
||||
|
||||
if( item instanceof TootNotification ){
|
||||
|
@ -252,75 +318,242 @@ public class ColumnViewHolder implements View.OnClickListener, Column.VisualCall
|
|||
if( TootNotification.TYPE_FAVOURITE.equals( n.type ) ){
|
||||
llBoosted.setVisibility( View.VISIBLE );
|
||||
ivBoosted.setImageResource( R.drawable.btn_favourite );
|
||||
tvBoostedTime.setText(TootStatus.formatTime( n.time_created_at )
|
||||
+"\n"+ account.getFullAcct( n.account )
|
||||
tvBoostedTime.setText( TootStatus.formatTime( n.time_created_at )
|
||||
+ "\n" + account.getFullAcct( n.account )
|
||||
);
|
||||
tvBoosted.setText( activity.getString( R.string.favourited_by, n.account.display_name ) );
|
||||
|
||||
if( n.status != null ) bindSub( activity, view, n.status,account );
|
||||
if( n.status != null ) bindSub( activity, view, n.status, account );
|
||||
}else if( TootNotification.TYPE_REBLOG.equals( n.type ) ){
|
||||
llBoosted.setVisibility( View.VISIBLE );
|
||||
ivBoosted.setImageResource( R.drawable.btn_boost );
|
||||
tvBoostedTime.setText(TootStatus.formatTime( n.time_created_at )
|
||||
+"\n"+ account.getFullAcct( n.account )
|
||||
tvBoostedTime.setText( TootStatus.formatTime( n.time_created_at )
|
||||
+ "\n" + account.getFullAcct( n.account )
|
||||
);
|
||||
tvBoosted.setText( activity.getString( R.string.boosted_by, n.account.display_name ) );
|
||||
if( n.status != null ) bindSub( activity, view, n.status,account );
|
||||
}else if( TootNotification.TYPE_FOLLOW.equals( n.type )){
|
||||
if( n.status != null ) bindSub( activity, view, n.status, account );
|
||||
}else if( TootNotification.TYPE_FOLLOW.equals( n.type ) ){
|
||||
llBoosted.setVisibility( View.VISIBLE );
|
||||
ivBoosted.setImageResource( R.drawable.btn_boost );
|
||||
tvBoostedTime.setText(TootStatus.formatTime( n.time_created_at )
|
||||
+"\n"+ account.getFullAcct( n.account )
|
||||
tvBoostedTime.setText( TootStatus.formatTime( n.time_created_at )
|
||||
+ "\n" + account.getFullAcct( n.account )
|
||||
);
|
||||
tvBoosted.setText( activity.getString( R.string.boosted_by, n.account.display_name ) );
|
||||
//
|
||||
llFollow.setVisibility( View.VISIBLE );
|
||||
ivFollow.setImageResource( R.drawable.btn_follow );
|
||||
ivFollow.setImageUrl( n.account.avatar_static, App1.getImageLoader() );
|
||||
tvFollowerName.setText( n.account.display_name );
|
||||
tvFollowerAcct.setText( account.getFullAcct( n.account ));
|
||||
tvFollowerAcct.setText( account.getFullAcct( n.account ) );
|
||||
}else if( TootNotification.TYPE_MENTION.equals( n.type ) ){
|
||||
if( n.status != null ) bindSub( activity, view, n.status,account );
|
||||
if( n.status != null ) bindSub( activity, view, n.status, account );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( item instanceof TootStatus ){
|
||||
TootStatus status = (TootStatus)item;
|
||||
TootStatus status = (TootStatus) item;
|
||||
if( status.reblog != null ){
|
||||
llBoosted.setVisibility( View.VISIBLE );
|
||||
ivBoosted.setImageResource( R.drawable.btn_boost );
|
||||
tvBoostedTime.setText(TootStatus.formatTime( status.time_created_at )
|
||||
+"\n"+ account.getFullAcct( status.account )
|
||||
tvBoostedTime.setText( TootStatus.formatTime( status.time_created_at )
|
||||
+ "\n" + account.getFullAcct( status.account )
|
||||
);
|
||||
tvBoosted.setText( activity.getString( R.string.boosted_by, status.account.display_name ) );
|
||||
bindSub( activity, view, status.reblog,account );
|
||||
bindSub( activity, view, status.reblog, account );
|
||||
}else{
|
||||
bindSub( activity, view, status ,account);
|
||||
bindSub( activity, view, status, account );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindSub( ActMain activity, View view, TootStatus status, SavedAccount account ){
|
||||
this.status = status;
|
||||
|
||||
llStatus.setVisibility( View.VISIBLE );
|
||||
tvTime.setText( TootStatus.formatTime( status.time_created_at )
|
||||
+"\n"+ account.getFullAcct( status.account )
|
||||
+ "\n" + account.getFullAcct( status.account )
|
||||
);
|
||||
tvName.setText( status.account.display_name );
|
||||
tvContent.setText( status.content );
|
||||
ivThumbnail.setImageUrl( status.account.avatar_static, App1.getImageLoader() );
|
||||
tvContent.setText( status.decoded_content );
|
||||
|
||||
// TODO media
|
||||
// Content warning
|
||||
if( TextUtils.isEmpty( status.spoiler_text ) ){
|
||||
llContentWarning.setVisibility( View.GONE );
|
||||
tvContent.setVisibility( View.VISIBLE );
|
||||
}else{
|
||||
llContentWarning.setVisibility( View.VISIBLE );
|
||||
tvContentWarning.setText( status.spoiler_text );
|
||||
showContent( ContentWarning.isShown( account.host, status.id, false ));
|
||||
}
|
||||
|
||||
btnBoost.getDrawable().setColorFilter(
|
||||
( status.reblogged ? 0xff0088ff : 0xff000000 )
|
||||
, PorterDuff.Mode.SRC_ATOP
|
||||
);
|
||||
if( status.media_attachments == null || status.media_attachments.isEmpty() ){
|
||||
flMedia.setVisibility( View.GONE );
|
||||
}else{
|
||||
flMedia.setVisibility( View.VISIBLE );
|
||||
setMedia( ivMedia1, status, 0 );
|
||||
setMedia( ivMedia2, status, 1 );
|
||||
setMedia( ivMedia3, status, 2 );
|
||||
setMedia( ivMedia4, status, 3 );
|
||||
|
||||
// hide sensitive media
|
||||
boolean is_shown = MediaShown.isShown( account.host,status.id, ! status.sensitive );
|
||||
btnShowMedia.setVisibility( ! is_shown ? View.VISIBLE : View.GONE );
|
||||
}
|
||||
|
||||
btnFavourite.getDrawable().setColorFilter(
|
||||
( status.favourited ? 0xff0088ff : 0xff000000 )
|
||||
, PorterDuff.Mode.SRC_ATOP
|
||||
);
|
||||
// todo show count of boost/fav
|
||||
Drawable d;
|
||||
int color;
|
||||
|
||||
color = ( status.reblogged ? 0xff0088ff : 0xff000000 );
|
||||
d = ContextCompat.getDrawable( activity, R.drawable.btn_boost ).mutate();
|
||||
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
|
||||
btnBoost.setCompoundDrawablesRelativeWithIntrinsicBounds( d, null, null, null );
|
||||
btnBoost.setText( Long.toString( status.reblogs_count ) );
|
||||
btnBoost.setTextColor( color );
|
||||
|
||||
color = ( status.favourited ? 0xff0088ff : 0xff000000 );
|
||||
d = ContextCompat.getDrawable( activity, R.drawable.btn_favourite ).mutate();
|
||||
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
|
||||
btnFavourite.setCompoundDrawablesRelativeWithIntrinsicBounds( d, null, null, null );
|
||||
btnFavourite.setText( Long.toString( status.favourites_count ) );
|
||||
btnFavourite.setTextColor( color );
|
||||
|
||||
}
|
||||
|
||||
private void showContent( boolean shown ){
|
||||
btnContentWarning.setText( shown ? R.string.hide : R.string.show );
|
||||
tvContent.setVisibility( shown ? View.VISIBLE : View.GONE );
|
||||
}
|
||||
|
||||
private void setMedia( NetworkImageView iv, TootStatus status, int idx ){
|
||||
if( idx >= status.media_attachments.size() ){
|
||||
iv.setVisibility( View.GONE );
|
||||
}else{
|
||||
iv.setVisibility( View.VISIBLE );
|
||||
TootAttachment ta = status.media_attachments.get( idx );
|
||||
String url = ta.preview_url;
|
||||
if( TextUtils.isEmpty( url ) ) url = ta.remote_url;
|
||||
iv.setImageUrl( url, App1.getImageLoader() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick( View v ){
|
||||
switch( v.getId() ){
|
||||
case R.id.btnHideMedia:
|
||||
MediaShown.save( account.host,status.id, false );
|
||||
btnShowMedia.setVisibility( View.VISIBLE );
|
||||
break;
|
||||
case R.id.btnShowMedia:
|
||||
MediaShown.save( account.host,status.id, true );
|
||||
btnShowMedia.setVisibility( View.GONE );
|
||||
break;
|
||||
case R.id.ivMedia1:
|
||||
clickMedia( 0 );
|
||||
break;
|
||||
case R.id.ivMedia2:
|
||||
clickMedia( 1 );
|
||||
break;
|
||||
case R.id.ivMedia3:
|
||||
clickMedia( 2 );
|
||||
break;
|
||||
case R.id.ivMedia4:
|
||||
clickMedia( 3 );
|
||||
break;
|
||||
case R.id.btnContentWarning:
|
||||
{
|
||||
boolean new_shown = (tvContent.getVisibility()==View.GONE);
|
||||
ContentWarning.save( account.host,status.id , new_shown);
|
||||
showContent( new_shown );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clickMedia( int i ){
|
||||
try{
|
||||
activity.openChromeTab( status.media_attachments.get( i ).remote_url );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderViewHolder implements View.OnClickListener {
|
||||
final View viewRoot;
|
||||
final NetworkImageView ivBackground;
|
||||
final TextView tvCreated;
|
||||
final NetworkImageView ivAvatar;
|
||||
final TextView tvDisplayName;
|
||||
final TextView tvAcct;
|
||||
final Button btnFollowing;
|
||||
final Button btnFollowers;
|
||||
final Button btnStatusCount;
|
||||
final TextView tvNote;
|
||||
TootAccount who;
|
||||
|
||||
public HeaderViewHolder( final ActMain activity, ListView parent ){
|
||||
viewRoot = activity.getLayoutInflater().inflate( R.layout.lv_list_header, parent, false );
|
||||
this.ivBackground = (NetworkImageView) viewRoot.findViewById( R.id.ivBackground );
|
||||
this.tvCreated = (TextView) viewRoot.findViewById( R.id.tvCreated );
|
||||
this.ivAvatar = (NetworkImageView) viewRoot.findViewById( R.id.ivAvatar );
|
||||
this.tvDisplayName = (TextView) viewRoot.findViewById( R.id.tvDisplayName );
|
||||
this.tvAcct = (TextView) viewRoot.findViewById( R.id.tvAcct );
|
||||
this.btnFollowing = (Button) viewRoot.findViewById( R.id.btnFollowing );
|
||||
this.btnFollowers = (Button) viewRoot.findViewById( R.id.btnFollowers );
|
||||
this.btnStatusCount = (Button) viewRoot.findViewById( R.id.btnStatusCount );
|
||||
this.tvNote = (TextView) viewRoot.findViewById( R.id.tvNote );
|
||||
|
||||
ivBackground.setOnClickListener( this );
|
||||
btnFollowing.setOnClickListener( this );
|
||||
btnFollowers.setOnClickListener( this );
|
||||
btnStatusCount.setOnClickListener( this );
|
||||
|
||||
}
|
||||
|
||||
public void bind( ActMain activity, SavedAccount access_info, TootAccount who ){
|
||||
this.who = who;
|
||||
if( who == null ){
|
||||
tvCreated.setText( "" );
|
||||
ivBackground.setImageDrawable( null );
|
||||
ivAvatar.setImageDrawable( null );
|
||||
tvDisplayName.setText( "" );
|
||||
tvAcct.setText( "" );
|
||||
tvNote.setText( "" );
|
||||
btnStatusCount.setText( activity.getString( R.string.statuses ) + "\n" + "?" );
|
||||
btnFollowing.setText( activity.getString( R.string.following ) + "\n" + "?" );
|
||||
btnFollowers.setText( activity.getString( R.string.followers ) + "\n" + "?" );
|
||||
}else{
|
||||
tvCreated.setText( TootStatus.formatTime( who.time_created_at ) );
|
||||
ivBackground.setImageUrl( who.header_static, App1.getImageLoader() );
|
||||
ivAvatar.setImageUrl( who.avatar_static, App1.getImageLoader() );
|
||||
tvDisplayName.setText( who.display_name );
|
||||
tvAcct.setText( access_info.getFullAcct( who ) );
|
||||
tvNote.setText( who.note );
|
||||
btnStatusCount.setText( activity.getString( R.string.statuses ) + "\n" + who.statuses_count );
|
||||
btnFollowing.setText( activity.getString( R.string.following ) + "\n" + who.following_count );
|
||||
btnFollowers.setText( activity.getString( R.string.followers ) + "\n" + who.followers_count );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick( View v ){
|
||||
switch( v.getId() ){
|
||||
case R.id.ivBackground:
|
||||
if( who != null ){
|
||||
activity.openBrowser( who.url );
|
||||
}
|
||||
break;
|
||||
case R.id.btnFollowing:
|
||||
Utils.showToast( activity, false, "not implemented" );
|
||||
break;
|
||||
case R.id.btnFollowers:
|
||||
Utils.showToast( activity, false, "not implemented" );
|
||||
break;
|
||||
case R.id.btnStatusCount:
|
||||
Utils.showToast( activity, false, "not implemented" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.json.JSONObject;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
import jp.juggler.subwaytooter.table.AccessToken;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.CancelChecker;
|
||||
import jp.juggler.subwaytooter.util.HTTPClient;
|
||||
|
@ -23,7 +22,6 @@ import jp.juggler.subwaytooter.table.ClientInfo;
|
|||
public class TootApiClient {
|
||||
private static final LogCategory log = new LogCategory( "TootApiClient" );
|
||||
|
||||
|
||||
public interface Callback {
|
||||
boolean isCancelled();
|
||||
|
||||
|
@ -42,14 +40,17 @@ public class TootApiClient {
|
|||
private String user_mail;
|
||||
private String password;
|
||||
|
||||
private SavedAccount account;
|
||||
|
||||
public void setUserInfo( String instance, String user_mail, String password ){
|
||||
this.instance = instance;
|
||||
this.user_mail = user_mail;
|
||||
this.password = password;
|
||||
}
|
||||
public void setAccessInfo( SavedAccount access_info ){
|
||||
this.instance = access_info.host;
|
||||
this.user_mail = access_info.user_mail;
|
||||
|
||||
public void setAccount( SavedAccount account ){
|
||||
this.instance = account.host;
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public TootApiResult get( String path ){
|
||||
|
@ -62,48 +63,46 @@ public class TootApiClient {
|
|||
} );
|
||||
|
||||
JSONObject client_info = null;
|
||||
JSONObject token_info = null;
|
||||
JSONObject token_info = ( account == null ? null : account.token_info );
|
||||
|
||||
for( ; ; ){
|
||||
if( callback.isCancelled() ) return null;
|
||||
if( client_info == null ){
|
||||
// DBにあるならそれを使う
|
||||
client_info = ClientInfo.load( instance );
|
||||
if( client_info != null ) continue;
|
||||
|
||||
callback.publishProgress( context.getString( R.string.register_app_to_server, instance ) );
|
||||
|
||||
// OAuth2 クライアント登録
|
||||
String client_name = "jp.juggler.subwaytooter." + UUID.randomUUID().toString();
|
||||
client.post_content = Utils.encodeUTF8(
|
||||
"client_name=" + Uri.encode( client_name )
|
||||
+ "&redirect_uris=urn:ietf:wg:oauth:2.0:oob"
|
||||
+ "&scopes=read write follow"
|
||||
);
|
||||
byte[] data = client.getHTTP( log, "https://" + instance + "/api/v1/apps" );
|
||||
if( callback.isCancelled() ) return null;
|
||||
|
||||
if( data == null ){
|
||||
return new TootApiResult( context.getString( R.string.network_error, client.last_error ) );
|
||||
}
|
||||
try{
|
||||
String result = Utils.decodeUTF8( data );
|
||||
// {"id":999,"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_id":"******","client_secret":"******"}
|
||||
client_info = new JSONObject( result );
|
||||
String error = Utils.optStringX( client_info, "error" );
|
||||
if( ! TextUtils.isEmpty( error ) ){
|
||||
return new TootApiResult( context.getString( R.string.api_error, error ) );
|
||||
}
|
||||
ClientInfo.save( instance, result );
|
||||
continue;
|
||||
}catch( JSONException ex ){
|
||||
ex.printStackTrace();
|
||||
return new TootApiResult( Utils.formatError( ex, "API data error" ) );
|
||||
}
|
||||
}
|
||||
if( token_info == null ){
|
||||
// DBにあるならそれを使う
|
||||
token_info = AccessToken.load( instance, user_mail );
|
||||
if( token_info != null ) continue;
|
||||
if( client_info == null ){
|
||||
// DBにあるならそれを使う
|
||||
client_info = ClientInfo.load( instance );
|
||||
if( client_info != null ) continue;
|
||||
|
||||
callback.publishProgress( context.getString( R.string.register_app_to_server, instance ) );
|
||||
|
||||
// OAuth2 クライアント登録
|
||||
String client_name = "jp.juggler.subwaytooter." + UUID.randomUUID().toString();
|
||||
client.post_content = Utils.encodeUTF8(
|
||||
"client_name=" + Uri.encode( client_name )
|
||||
+ "&redirect_uris=urn:ietf:wg:oauth:2.0:oob"
|
||||
+ "&scopes=read write follow"
|
||||
);
|
||||
byte[] data = client.getHTTP( log, "https://" + instance + "/api/v1/apps" );
|
||||
if( callback.isCancelled() ) return null;
|
||||
|
||||
if( data == null ){
|
||||
return new TootApiResult( context.getString( R.string.network_error, client.last_error ) );
|
||||
}
|
||||
try{
|
||||
String result = Utils.decodeUTF8( data );
|
||||
// {"id":999,"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_id":"******","client_secret":"******"}
|
||||
client_info = new JSONObject( result );
|
||||
String error = Utils.optStringX( client_info, "error" );
|
||||
if( ! TextUtils.isEmpty( error ) ){
|
||||
return new TootApiResult( context.getString( R.string.api_error, error ) );
|
||||
}
|
||||
ClientInfo.save( instance, result );
|
||||
continue;
|
||||
}catch( JSONException ex ){
|
||||
ex.printStackTrace();
|
||||
return new TootApiResult( Utils.formatError( ex, "API data error" ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( password == null ){
|
||||
// 手動でアクセストークンを再取得しなければいけない
|
||||
|
@ -115,8 +114,8 @@ public class TootApiClient {
|
|||
// アクセストークンの取得
|
||||
//
|
||||
client.post_content = Utils.encodeUTF8(
|
||||
"client_id=" + Uri.encode( Utils.optStringX( client_info , "client_id" ) )
|
||||
+ "&client_secret=" + Uri.encode( Utils.optStringX( client_info, "client_secret" ) )
|
||||
"client_id=" + Uri.encode( Utils.optStringX( client_info, "client_id" ) )
|
||||
+ "&client_secret=" + Uri.encode( Utils.optStringX( client_info, "client_secret" ) )
|
||||
+ "&grant_type=password"
|
||||
+ "&username=" + Uri.encode( user_mail )
|
||||
+ "&password=" + Uri.encode( password )
|
||||
|
@ -129,7 +128,7 @@ public class TootApiClient {
|
|||
if( data == null ){
|
||||
return new TootApiResult( context.getString( R.string.network_error, client.last_error ) );
|
||||
}
|
||||
|
||||
|
||||
try{
|
||||
String result = Utils.decodeUTF8( data );
|
||||
// {"access_token":"******","token_type":"bearer","scope":"read","created_at":1492334641}
|
||||
|
@ -138,53 +137,55 @@ public class TootApiClient {
|
|||
if( ! TextUtils.isEmpty( error ) ){
|
||||
return new TootApiResult( context.getString( R.string.api_error, error ) );
|
||||
}
|
||||
AccessToken.save( instance, user_mail, result );
|
||||
if( account != null ){
|
||||
account.updateTokenInfo( token_info );
|
||||
}
|
||||
continue;
|
||||
}catch( JSONException ex ){
|
||||
ex.printStackTrace();
|
||||
return new TootApiResult( Utils.formatError( ex, "API data error" ) );
|
||||
}
|
||||
}
|
||||
|
||||
// アクセストークンを使ってAPIを呼び出す
|
||||
{
|
||||
callback.publishProgress( context.getString( R.string.request_api, path ) );
|
||||
|
||||
// アクセストークンを使ってAPIを呼び出す
|
||||
{
|
||||
callback.publishProgress( context.getString( R.string.request_api, path ) );
|
||||
|
||||
client.post_content = null;
|
||||
client.extra_header = new String[]{
|
||||
"Authorization", "Bearer "+ Utils.optStringX( token_info,"access_token")
|
||||
};
|
||||
byte[] data = client.getHTTP( log, "https://" + instance + path );
|
||||
if( callback.isCancelled() ) return null;
|
||||
|
||||
// TODO: アクセストークンが無効な場合はどうなる?
|
||||
// TODO: アプリIDが無効な場合はどうなる?
|
||||
|
||||
if( data == null ){
|
||||
return new TootApiResult( context.getString( R.string.network_error, client.last_error ) );
|
||||
}
|
||||
|
||||
try{
|
||||
String result = Utils.decodeUTF8( data );
|
||||
if( result.startsWith( "[" ) ){
|
||||
JSONArray array = new JSONArray( result );
|
||||
return new TootApiResult( result,array );
|
||||
}else{
|
||||
JSONObject json = new JSONObject( result );
|
||||
|
||||
String error = Utils.optStringX( client_info, "error" );
|
||||
if( ! TextUtils.isEmpty( error ) ){
|
||||
return new TootApiResult( context.getString( R.string.api_error, error ) );
|
||||
}
|
||||
return new TootApiResult( result,json );
|
||||
client.post_content = null;
|
||||
client.extra_header = new String[]{
|
||||
"Authorization", "Bearer " + Utils.optStringX( token_info, "access_token" )
|
||||
};
|
||||
byte[] data = client.getHTTP( log, "https://" + instance + path );
|
||||
if( callback.isCancelled() ) return null;
|
||||
|
||||
// TODO: アクセストークンが無効な場合はどうなる?
|
||||
// TODO: アプリIDが無効な場合はどうなる?
|
||||
|
||||
if( data == null ){
|
||||
return new TootApiResult( context.getString( R.string.network_error, client.last_error ) );
|
||||
}
|
||||
|
||||
try{
|
||||
String result = Utils.decodeUTF8( data );
|
||||
if( result.startsWith( "[" ) ){
|
||||
JSONArray array = new JSONArray( result );
|
||||
return new TootApiResult( token_info, result, array );
|
||||
}else{
|
||||
JSONObject json = new JSONObject( result );
|
||||
|
||||
String error = Utils.optStringX( json, "error" );
|
||||
if( ! TextUtils.isEmpty( error ) ){
|
||||
return new TootApiResult( context.getString( R.string.api_error, error ) );
|
||||
}
|
||||
}catch( JSONException ex ){
|
||||
ex.printStackTrace();
|
||||
return new TootApiResult( Utils.formatError( ex, "API data error" ) );
|
||||
return new TootApiResult( token_info, result, json );
|
||||
}
|
||||
}catch( JSONException ex ){
|
||||
ex.printStackTrace();
|
||||
return new TootApiResult( Utils.formatError( ex, "API data error" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,16 +8,19 @@ public class TootApiResult {
|
|||
public JSONObject object;
|
||||
public JSONArray array;
|
||||
public String json;
|
||||
public JSONObject token_info;
|
||||
public TootApiResult( String error ){
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public TootApiResult( String json,JSONObject object ){
|
||||
public TootApiResult( JSONObject token_info,String json,JSONObject object ){
|
||||
this.token_info = token_info;
|
||||
this.json = json;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public TootApiResult( String json,JSONArray array ){
|
||||
public TootApiResult(JSONObject token_info, String json,JSONArray array ){
|
||||
this.token_info = token_info;
|
||||
this.json = json;
|
||||
this.array = array;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ public class TootAccount {
|
|||
// URL to the header static image (gif)
|
||||
public String header_static;
|
||||
|
||||
public long time_created_at;
|
||||
|
||||
public static TootAccount parse( LogCategory log, JSONObject src, TootAccount dst ){
|
||||
if( src == null ) return null;
|
||||
try{
|
||||
|
@ -80,6 +82,8 @@ public class TootAccount {
|
|||
dst.avatar_static = Utils.optStringX( src, "avatar_static" ); // "https:\/\/mastodon.juggler.jp\/system\/accounts\/avatars\/000\/000\/148\/original\/0a468974fac5a448.PNG?1492081886",
|
||||
dst.header = Utils.optStringX( src, "header" ); // "https:\/\/mastodon.juggler.jp\/headers\/original\/missing.png"
|
||||
dst.header_static = Utils.optStringX( src, "header_static" ); // "https:\/\/mastodon.juggler.jp\/headers\/original\/missing.png"}
|
||||
|
||||
dst.time_created_at = TootStatus.parseTime( log,dst.created_at );
|
||||
return dst;
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package jp.juggler.subwaytooter.api.entity;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
@ -9,10 +10,10 @@ import java.text.ParseException;
|
|||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
|
@ -83,6 +84,8 @@ public class TootStatus {
|
|||
public String application;
|
||||
|
||||
public long time_created_at;
|
||||
|
||||
public Spannable decoded_content;
|
||||
|
||||
public static TootStatus parse( LogCategory log, JSONObject src ){
|
||||
|
||||
|
@ -113,6 +116,7 @@ public class TootStatus {
|
|||
status.application = Utils.optStringX( src, "application" ); // null
|
||||
|
||||
status.time_created_at = parseTime( log, status.created_at );
|
||||
status.decoded_content = HTMLDecoder.decodeHTML(status.content);
|
||||
|
||||
return status;
|
||||
}catch( Throwable ex ){
|
||||
|
|
|
@ -4,8 +4,15 @@ import android.app.Dialog;
|
|||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.EditText;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jp.juggler.subwaytooter.ActMain;
|
||||
import jp.juggler.subwaytooter.R;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
@ -22,7 +29,7 @@ public class LoginForm {
|
|||
|
||||
public static void showLoginForm(final ActMain activity,final LoginFormCallback callback){
|
||||
final View view = activity.getLayoutInflater().inflate( R.layout.dlg_account_add, null, false );
|
||||
final EditText etInstance = (EditText) view.findViewById( R.id.etInstance );
|
||||
final AutoCompleteTextView etInstance = (AutoCompleteTextView) view.findViewById( R.id.etInstance );
|
||||
final EditText etUserMail = (EditText) view.findViewById( R.id.etUserMail );
|
||||
final EditText etUserPassword = (EditText) view.findViewById( R.id.etUserPassword );
|
||||
final Dialog dialog = new Dialog( activity );
|
||||
|
@ -54,8 +61,36 @@ public class LoginForm {
|
|||
dialog.cancel();
|
||||
}
|
||||
} );
|
||||
|
||||
ArrayList<String> instance_list = new ArrayList<>( );
|
||||
try{
|
||||
InputStream is = activity.getResources().openRawResource( R.raw.server_list );
|
||||
try{
|
||||
BufferedReader br = new BufferedReader( new InputStreamReader( is,"UTF-8" ) );
|
||||
for(;;){
|
||||
String s = br.readLine();
|
||||
if( s == null ) break;
|
||||
s= s.trim();
|
||||
if( s.length() > 0 ) instance_list.add( s );
|
||||
}
|
||||
}finally{
|
||||
try{
|
||||
is.close();
|
||||
}catch(Throwable ignored){
|
||||
|
||||
}
|
||||
}
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace( );
|
||||
}
|
||||
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(activity, R.layout.lv_instance_dropdown, instance_list);
|
||||
adapter.setDropDownViewResource( R.layout.lv_instance_dropdown );
|
||||
etInstance.setAdapter(adapter);
|
||||
|
||||
//noinspection ConstantConditions
|
||||
dialog.getWindow().setLayout( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT );
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,78 +1,78 @@
|
|||
package jp.juggler.subwaytooter.table;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jp.juggler.subwaytooter.App1;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
|
||||
public class AccessToken {
|
||||
|
||||
static final LogCategory log = new LogCategory( "AccessToken" );
|
||||
|
||||
static final String table = "access_token";
|
||||
|
||||
static final String COL_HOST = "h";
|
||||
static final String COL_USER_MAIL = "um";
|
||||
static final String COL_TOKEN = "t";
|
||||
|
||||
public String host;
|
||||
public String user_mail;
|
||||
|
||||
public static void onDBCreate( SQLiteDatabase db ){
|
||||
db.execSQL(
|
||||
"create table if not exists " + table
|
||||
+ "(_id INTEGER PRIMARY KEY"
|
||||
+ ",h text not null"
|
||||
+ ",um text not null"
|
||||
+ ",t text not null"
|
||||
+ ")"
|
||||
);
|
||||
db.execSQL(
|
||||
"create unique index if not exists " + table + "_host on " + table
|
||||
+ "(h"
|
||||
+ ",um"
|
||||
+ ")"
|
||||
);
|
||||
}
|
||||
|
||||
public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
|
||||
|
||||
}
|
||||
|
||||
public static JSONObject load( String instance, String user_mail ){
|
||||
try{
|
||||
Cursor cursor = App1.getDB().query( table, null, "h=? and um=?", new String[]{ instance, user_mail }, null, null, null );
|
||||
try{
|
||||
if( cursor.moveToFirst() ){
|
||||
return new JSONObject( cursor.getString( cursor.getColumnIndex( COL_TOKEN ) ) );
|
||||
}
|
||||
}finally{
|
||||
cursor.close();
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "load failed." );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void save( String host, String user_mail, String json ){
|
||||
try{
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put( COL_HOST, host );
|
||||
cv.put( COL_USER_MAIL, user_mail );
|
||||
cv.put( COL_TOKEN, json );
|
||||
App1.getDB().replace( table, null, cv );
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "save failed." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//package jp.juggler.subwaytooter.table;
|
||||
//
|
||||
//import android.content.ContentValues;
|
||||
//import android.database.Cursor;
|
||||
//import android.database.sqlite.SQLiteDatabase;
|
||||
//
|
||||
//import org.json.JSONException;
|
||||
//import org.json.JSONObject;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//
|
||||
//import jp.juggler.subwaytooter.App1;
|
||||
//import jp.juggler.subwaytooter.util.LogCategory;
|
||||
//
|
||||
//public class AccessToken {
|
||||
//
|
||||
// static final LogCategory log = new LogCategory( "AccessToken" );
|
||||
//
|
||||
// static final String table = "access_token";
|
||||
//
|
||||
// static final String COL_HOST = "h";
|
||||
// static final String COL_USER_MAIL = "um";
|
||||
//
|
||||
//
|
||||
// public String host;
|
||||
// public String user_mail;
|
||||
//
|
||||
// public static void onDBCreate( SQLiteDatabase db ){
|
||||
// db.execSQL(
|
||||
// "create table if not exists " + table
|
||||
// + "(_id INTEGER PRIMARY KEY"
|
||||
// + ",h text not null"
|
||||
// + ",um text not null"
|
||||
// + ",t text not null"
|
||||
// + ")"
|
||||
// );
|
||||
// db.execSQL(
|
||||
// "create unique index if not exists " + table + "_host on " + table
|
||||
// + "(h"
|
||||
// + ",um"
|
||||
// + ")"
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public static JSONObject load( String instance, String user_mail ){
|
||||
// try{
|
||||
// Cursor cursor = App1.getDB().query( table, null, "h=? and um=?", new String[]{ instance, user_mail }, null, null, null );
|
||||
// try{
|
||||
// if( cursor.moveToFirst() ){
|
||||
// return new JSONObject( cursor.getString( cursor.getColumnIndex( COL_TOKEN ) ) );
|
||||
// }
|
||||
// }finally{
|
||||
// cursor.close();
|
||||
// }
|
||||
// }catch( Throwable ex ){
|
||||
// log.e( ex, "load failed." );
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public static void save( String host, String user_mail, String json ){
|
||||
// try{
|
||||
// ContentValues cv = new ContentValues();
|
||||
// cv.put( COL_HOST, host );
|
||||
// cv.put( COL_USER_MAIL, user_mail );
|
||||
// cv.put( COL_TOKEN, json );
|
||||
// App1.getDB().replace( table, null, cv );
|
||||
// }catch( Throwable ex ){
|
||||
// log.e( ex, "save failed." );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package jp.juggler.subwaytooter.table;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import jp.juggler.subwaytooter.App1;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
|
||||
public class ContentWarning {
|
||||
private static final LogCategory log = new LogCategory( "ContentWarning" );
|
||||
|
||||
private static final String table = "content_warning";
|
||||
private static final String COL_HOST = "h";
|
||||
private static final String COL_STATUS_ID = "si";
|
||||
private static final String COL_SHOWN = "sh";
|
||||
|
||||
public static void onDBCreate( SQLiteDatabase db ){
|
||||
db.execSQL(
|
||||
"create table if not exists " + table
|
||||
+ "(_id INTEGER PRIMARY KEY"
|
||||
+ ",h text not null"
|
||||
+ ",si integer not null"
|
||||
+ ",sh integer not null"
|
||||
+ ")"
|
||||
);
|
||||
db.execSQL(
|
||||
"create unique index if not exists " + table + "_status_id on " + table + "(h,si,sh)"
|
||||
);
|
||||
}
|
||||
|
||||
public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
|
||||
|
||||
}
|
||||
|
||||
private static final String[] projection_shown = new String[]{COL_SHOWN};
|
||||
|
||||
public static boolean isShown( String host,long status_id ,boolean default_value ){
|
||||
try{
|
||||
Cursor cursor = App1.getDB().query( table, projection_shown, "h=? and si=?", new String[]{host, Long.toString(status_id) }, null, null, null );
|
||||
try{
|
||||
if( cursor.moveToFirst() ){
|
||||
return ( 0 != cursor.getInt( cursor.getColumnIndex( COL_SHOWN ) ) );
|
||||
}
|
||||
}finally{
|
||||
cursor.close();
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "load failed." );
|
||||
}
|
||||
return default_value ;
|
||||
}
|
||||
|
||||
public static void save( String host,long status_id ,boolean is_shown ){
|
||||
try{
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put( COL_HOST, host );
|
||||
cv.put( COL_STATUS_ID, status_id );
|
||||
cv.put( COL_SHOWN, is_shown ? 1:0 );
|
||||
App1.getDB().replace( table, null, cv );
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "save failed." );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package jp.juggler.subwaytooter.table;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import jp.juggler.subwaytooter.App1;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
|
||||
public class MediaShown {
|
||||
private static final LogCategory log = new LogCategory( "MediaShown" );
|
||||
|
||||
private static final String table = "media_shown";
|
||||
private static final String COL_HOST = "h";
|
||||
private static final String COL_STATUS_ID = "si";
|
||||
private static final String COL_SHOWN = "sh";
|
||||
|
||||
public static void onDBCreate( SQLiteDatabase db ){
|
||||
db.execSQL(
|
||||
"create table if not exists " + table
|
||||
+ "(_id INTEGER PRIMARY KEY"
|
||||
+ ",h text not null"
|
||||
+ ",si integer not null"
|
||||
+ ",sh integer not null"
|
||||
+ ")"
|
||||
);
|
||||
db.execSQL(
|
||||
"create unique index if not exists " + table + "_status_id on " + table + "(h,si,sh)"
|
||||
);
|
||||
}
|
||||
|
||||
public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
|
||||
|
||||
}
|
||||
|
||||
private static final String[] projection_shown = new String[]{COL_SHOWN};
|
||||
|
||||
public static boolean isShown( String host,long status_id ,boolean default_value ){
|
||||
try{
|
||||
Cursor cursor = App1.getDB().query( table, projection_shown, "h=? and si=?", new String[]{host, Long.toString(status_id) }, null, null, null );
|
||||
try{
|
||||
if( cursor.moveToFirst() ){
|
||||
return ( 0 != cursor.getInt( cursor.getColumnIndex( COL_SHOWN ) ) );
|
||||
}
|
||||
}finally{
|
||||
cursor.close();
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "load failed." );
|
||||
}
|
||||
return default_value ;
|
||||
}
|
||||
|
||||
public static void save( String host,long status_id ,boolean is_shown ){
|
||||
try{
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put( COL_HOST, host );
|
||||
cv.put( COL_STATUS_ID, status_id );
|
||||
cv.put( COL_SHOWN, is_shown ? 1:0 );
|
||||
App1.getDB().replace( table, null, cv );
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "save failed." );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package jp.juggler.subwaytooter.table;
|
|||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -17,33 +18,35 @@ public class SavedAccount extends TootAccount{
|
|||
|
||||
static final String table = "access_info";
|
||||
|
||||
static final String COL_ID = BaseColumns._ID;
|
||||
static final String COL_HOST = "h";
|
||||
static final String COL_USER_MAIL = "um";
|
||||
static final String COL_USER = "u";
|
||||
static final String COL_ACCOUNT = "a";
|
||||
static final String COL_TOKEN = "t";
|
||||
static final String COL_LOGIN_REQUIRED = "lr";
|
||||
|
||||
// login information
|
||||
public String host;
|
||||
public String user_mail;
|
||||
public boolean login_required;
|
||||
public static final long INVALID_ID = -1L;
|
||||
|
||||
// login information
|
||||
public long db_id = INVALID_ID;
|
||||
public String host;
|
||||
public String user;
|
||||
public boolean login_required;
|
||||
public JSONObject token_info;
|
||||
|
||||
public static void onDBCreate( SQLiteDatabase db ){
|
||||
db.execSQL(
|
||||
"create table if not exists " + table
|
||||
+ "(_id INTEGER PRIMARY KEY"
|
||||
+ ",u text not null"
|
||||
+ ",h text not null"
|
||||
+ ",um text not null"
|
||||
+ ",a text not null"
|
||||
+ ",t text not null"
|
||||
+ ",lr integer default 0"
|
||||
+ ")"
|
||||
);
|
||||
db.execSQL(
|
||||
"create unique index if not exists " + table + "_host on " + table
|
||||
+ "(h"
|
||||
+ ",um"
|
||||
+ ")"
|
||||
);
|
||||
db.execSQL("create index if not exists " + table + "_user on " + table + "(u)" );
|
||||
db.execSQL("create index if not exists " + table + "_host on " + table + "(h,u)" );
|
||||
}
|
||||
|
||||
public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
|
||||
|
@ -54,29 +57,41 @@ public class SavedAccount extends TootAccount{
|
|||
JSONObject src = new JSONObject( cursor.getString( cursor.getColumnIndex( COL_ACCOUNT ) ) );
|
||||
SavedAccount dst = (SavedAccount)parse(log,src,new SavedAccount());
|
||||
if( dst != null){
|
||||
dst.db_id = cursor.getLong( cursor.getColumnIndex( COL_ID ) );
|
||||
dst.host = cursor.getString( cursor.getColumnIndex( COL_HOST ) );
|
||||
dst.user_mail = cursor.getString( cursor.getColumnIndex( COL_USER_MAIL ) );
|
||||
dst.user = cursor.getString( cursor.getColumnIndex( COL_USER ) );
|
||||
dst.login_required = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_LOGIN_REQUIRED ) ) );
|
||||
dst.token_info = new JSONObject( cursor.getString( cursor.getColumnIndex( COL_TOKEN ) ) );
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
public static void save( LogCategory log,String instance, String user_mail, JSONObject data ){
|
||||
public static long insert( LogCategory log,String host, String user, JSONObject account,JSONObject token ){
|
||||
try{
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put( COL_HOST, instance );
|
||||
cv.put( COL_USER_MAIL, user_mail );
|
||||
cv.put( COL_ACCOUNT, data.toString() );
|
||||
App1.getDB().replace( table, null, cv );
|
||||
cv.put( COL_HOST, host );
|
||||
cv.put( COL_USER, user );
|
||||
cv.put( COL_ACCOUNT, account.toString() );
|
||||
cv.put( COL_TOKEN, token.toString() );
|
||||
return App1.getDB().insert( table, null, cv );
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "saveAccount failed." );
|
||||
}
|
||||
return INVALID_ID;
|
||||
}
|
||||
|
||||
public static SavedAccount loadAccount( LogCategory log, String instance, String user_mail ){
|
||||
public void updateTokenInfo( JSONObject token_info ){
|
||||
if( db_id != INVALID_ID ){
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put( COL_TOKEN, token_info.toString() );
|
||||
App1.getDB().update( table, cv, COL_ID + "=?", new String[]{ Long.toString(db_id) } );
|
||||
}
|
||||
}
|
||||
|
||||
public static SavedAccount loadAccount( LogCategory log, long id ){
|
||||
try{
|
||||
Cursor cursor = App1.getDB().query( table, null, "h=? and um=?", new String[]{ instance, user_mail }, null, null, null );
|
||||
Cursor cursor = App1.getDB().query( table, null, COL_ID+"=?", new String[]{ Long.toString(id) }, null, null, null );
|
||||
try{
|
||||
if( cursor.moveToFirst() ){
|
||||
return parse( log,cursor );
|
||||
|
@ -89,7 +104,7 @@ public class SavedAccount extends TootAccount{
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static ArrayList< SavedAccount > loadAccountList(LogCategory log){
|
||||
ArrayList< SavedAccount > result = new ArrayList<>();
|
||||
|
||||
|
@ -109,10 +124,6 @@ public class SavedAccount extends TootAccount{
|
|||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasAccount( LogCategory log,String instance, String user_mail ){
|
||||
return null != loadAccount( log,instance,user_mail );
|
||||
}
|
||||
|
||||
public String getFullAcct(TootAccount who ){
|
||||
if( who== null || who.acct ==null ) return "@?";
|
||||
if( -1 != who.acct.indexOf( '@' ) ){
|
||||
|
|
|
@ -0,0 +1,538 @@
|
|||
package jp.juggler.subwaytooter.util;
|
||||
|
||||
import android.text.Html;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.View;
|
||||
|
||||
import com.emojione.Emojione;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HTMLDecoder {
|
||||
static final LogCategory log = new LogCategory( "HTMLDecoder" );
|
||||
|
||||
static final int OPEN_TYPE_OPENCLOSE = 1;
|
||||
static final int OPEN_TYPE_OPEN = 2;
|
||||
static final int OPEN_TYPE_CLOSE = 3;
|
||||
|
||||
static final String TAG_TEXT = "<>text";
|
||||
static final String TAG_END = "<>end";
|
||||
|
||||
static final Pattern reTag = Pattern.compile( "<(/?)(\\w+)" );
|
||||
static final Pattern reTagEnd = Pattern.compile( "(/?)>$" );
|
||||
static final Pattern reHref = Pattern.compile( "\\bhref=\"([^\"]*)\"" );
|
||||
|
||||
static class TokenParser {
|
||||
|
||||
final String src;
|
||||
int next;
|
||||
|
||||
String tag;
|
||||
int open_type;
|
||||
String text;
|
||||
|
||||
public TokenParser( String src ){
|
||||
this.src = src;
|
||||
this.next = 0;
|
||||
eat();
|
||||
}
|
||||
|
||||
void eat(){
|
||||
// end?
|
||||
if( next >= src.length() ){
|
||||
tag = TAG_END;
|
||||
open_type = OPEN_TYPE_OPENCLOSE;
|
||||
return;
|
||||
}
|
||||
// text ?
|
||||
int end = src.indexOf( '<', next );
|
||||
if( end == - 1 ) end = src.length();
|
||||
if( end > next ){
|
||||
this.text = src.substring( next, end );
|
||||
this.tag = TAG_TEXT;
|
||||
this.open_type = OPEN_TYPE_OPENCLOSE;
|
||||
next = end;
|
||||
return;
|
||||
}
|
||||
// tag ?
|
||||
end = src.indexOf( '>', next );
|
||||
if( end == - 1 ){
|
||||
end = src.length();
|
||||
}else{
|
||||
++ end;
|
||||
}
|
||||
text = src.substring( next, end );
|
||||
next = end;
|
||||
Matcher m = reTag.matcher( text );
|
||||
if( m.find() ){
|
||||
boolean is_close = ! TextUtils.isEmpty( m.group( 1 ) );
|
||||
tag = m.group( 2 ).toLowerCase();
|
||||
Matcher m2 = reTagEnd.matcher( text );
|
||||
boolean is_openclose = false;
|
||||
if( m2.find() ){
|
||||
is_openclose = ! TextUtils.isEmpty( m2.group( 1 ) );
|
||||
}
|
||||
open_type = is_close ? OPEN_TYPE_CLOSE : is_openclose ? OPEN_TYPE_OPENCLOSE : OPEN_TYPE_OPEN;
|
||||
}else{
|
||||
tag = TAG_TEXT;
|
||||
this.open_type = OPEN_TYPE_OPENCLOSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface LinkClickCallback {
|
||||
void onClickLink( String url );
|
||||
}
|
||||
|
||||
public static LinkClickCallback link_callback;
|
||||
|
||||
static final boolean DEBUG_HTML_PARSER = false;
|
||||
|
||||
static class Node {
|
||||
final ArrayList< Node > child_nodes = new ArrayList<>();
|
||||
|
||||
String tag;
|
||||
String text;
|
||||
|
||||
public Node(){
|
||||
tag = "<>root";
|
||||
text = "";
|
||||
}
|
||||
|
||||
public Node( TokenParser t ){
|
||||
this.tag = t.tag;
|
||||
this.text = t.text;
|
||||
}
|
||||
|
||||
public void parseChild( TokenParser t, String indent ){
|
||||
if( DEBUG_HTML_PARSER ) log.d( "parseChild: %s(%s", indent, tag );
|
||||
for( ; ; ){
|
||||
if( TAG_END.equals( t.tag ) ) break;
|
||||
if( OPEN_TYPE_CLOSE == t.open_type ){
|
||||
t.eat();
|
||||
break;
|
||||
}
|
||||
int open_type = t.open_type;
|
||||
Node child = new Node( t );
|
||||
child_nodes.add( child );
|
||||
t.eat();
|
||||
|
||||
if( DEBUG_HTML_PARSER )
|
||||
log.d( "parseChild: %s|%s %s [%s]", indent, child.tag, open_type, child.text );
|
||||
|
||||
if( OPEN_TYPE_OPEN == open_type ){
|
||||
child.parseChild( t, indent + "--" );
|
||||
}
|
||||
}
|
||||
if( DEBUG_HTML_PARSER ) log.d( "parseChild: %s)%s", indent, tag );
|
||||
}
|
||||
|
||||
|
||||
|
||||
String decodeEmoji( String s ){
|
||||
return Emojione.shortnameToUnicode( s, false );
|
||||
}
|
||||
|
||||
public void encodeSpan( SpannableStringBuilder sb ){
|
||||
if( TAG_TEXT.equals( tag ) ){
|
||||
sb.append( decodeEntity( decodeEmoji( text ) ) );
|
||||
return;
|
||||
}
|
||||
if( DEBUG_HTML_PARSER ) sb.append( "(start " + tag + ")" );
|
||||
|
||||
int start = sb.length();
|
||||
|
||||
for( Node child : child_nodes ){
|
||||
child.encodeSpan( sb );
|
||||
}
|
||||
|
||||
if( "a".equals( tag ) ){
|
||||
Matcher m = reHref.matcher( text );
|
||||
if( m.find() ){
|
||||
final String href = decodeEntity( m.group( 1 ) ).toString();
|
||||
if( ! TextUtils.isEmpty( href ) ){
|
||||
sb.setSpan( new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick( View widget ){
|
||||
if( link_callback != null ){
|
||||
link_callback.onClickLink( href );
|
||||
}
|
||||
}
|
||||
}, start, sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( DEBUG_HTML_PARSER ) sb.append( "(end " + tag + ")" );
|
||||
|
||||
if( "br".equals( tag ) ) sb.append( '\n' );
|
||||
if( "p".equals( tag ) ){
|
||||
if( sb.charAt( sb.length()-1 ) != '\n' ) sb.append( '\n' );
|
||||
sb.append( '\n' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static SpannableStringBuilder decodeHTML( String src ){
|
||||
try{
|
||||
TokenParser tracker = new TokenParser( src );
|
||||
Node rootNode = new Node();
|
||||
rootNode.parseChild( tracker, "" );
|
||||
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
|
||||
rootNode.encodeSpan( sb );
|
||||
int end = sb.length();
|
||||
while( end > 0 && Character.isWhitespace( sb.charAt( end-1 ) ) ) --end;
|
||||
if( end < sb.length() ){
|
||||
sb.delete( end,sb.length() );
|
||||
}
|
||||
|
||||
return sb;
|
||||
|
||||
}catch( Throwable ex ){
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final HashMap< String, Character > entity_map = new HashMap<>();
|
||||
|
||||
private static void _addEntity( String s, char c ){
|
||||
entity_map.put( s, c );
|
||||
}
|
||||
|
||||
private static char chr( int num ){
|
||||
return (char) num;
|
||||
}
|
||||
|
||||
static final Pattern reEntity = Pattern.compile( "&(#?)(\\w+);" );
|
||||
|
||||
static CharSequence decodeEntity( String src ){
|
||||
StringBuilder sb = null;
|
||||
Matcher m = reEntity.matcher( src );
|
||||
int last_end = 0;
|
||||
while( m.find() ){
|
||||
if(sb==null) sb = new StringBuilder();
|
||||
int start = m.start();
|
||||
int end = m.end();
|
||||
try{
|
||||
if( start > last_end ){
|
||||
sb.append( src.substring( last_end, start ) );
|
||||
}
|
||||
boolean is_numeric = m.group( 1 ).length() > 0;
|
||||
String part = m.group( 2 );
|
||||
if( ! is_numeric ){
|
||||
Character c = entity_map.get( part );
|
||||
if( c != null ){
|
||||
sb.append( (char) c );
|
||||
continue;
|
||||
}
|
||||
}else{
|
||||
int c;
|
||||
try{
|
||||
if( part.charAt( 0 ) == 'x' ){
|
||||
c = Integer.parseInt( part.substring( 1 ), 16 );
|
||||
}else{
|
||||
c = Integer.parseInt( part, 10 );
|
||||
}
|
||||
sb.append( (char) c );
|
||||
continue;
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
sb.append( src.substring( start, end ) );
|
||||
}finally{
|
||||
last_end = end;
|
||||
}
|
||||
}
|
||||
|
||||
// 全くマッチしなかった
|
||||
if( sb == null ) return src;
|
||||
|
||||
int end = src.length();
|
||||
if( end > last_end ){
|
||||
sb.append( src.substring( last_end, end ) );
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static void init1(){
|
||||
_addEntity( "amp", '&' ); // ampersand
|
||||
_addEntity( "gt", '>' ); // greater than
|
||||
_addEntity( "lt", '<' ); // less than
|
||||
_addEntity( "quot", '"' ); // double quote
|
||||
_addEntity( "apos", '\'' ); // single quote
|
||||
_addEntity( "AElig", chr( 198 ) ); // capital AE diphthong (ligature)
|
||||
_addEntity( "Aacute", chr( 193 ) ); // capital A, acute accent
|
||||
_addEntity( "Acirc", chr( 194 ) ); // capital A, circumflex accent
|
||||
_addEntity( "Agrave", chr( 192 ) ); // capital A, grave accent
|
||||
_addEntity( "Aring", chr( 197 ) ); // capital A, ring
|
||||
_addEntity( "Atilde", chr( 195 ) ); // capital A, tilde
|
||||
_addEntity( "Auml", chr( 196 ) ); // capital A, dieresis or umlaut mark
|
||||
_addEntity( "Ccedil", chr( 199 ) ); // capital C, cedilla
|
||||
_addEntity( "ETH", chr( 208 ) ); // capital Eth, Icelandic
|
||||
_addEntity( "Eacute", chr( 201 ) ); // capital E, acute accent
|
||||
_addEntity( "Ecirc", chr( 202 ) ); // capital E, circumflex accent
|
||||
_addEntity( "Egrave", chr( 200 ) ); // capital E, grave accent
|
||||
_addEntity( "Euml", chr( 203 ) ); // capital E, dieresis or umlaut mark
|
||||
_addEntity( "Iacute", chr( 205 ) ); // capital I, acute accent
|
||||
_addEntity( "Icirc", chr( 206 ) ); // capital I, circumflex accent
|
||||
_addEntity( "Igrave", chr( 204 ) ); // capital I, grave accent
|
||||
_addEntity( "Iuml", chr( 207 ) ); // capital I, dieresis or umlaut mark
|
||||
_addEntity( "Ntilde", chr( 209 ) ); // capital N, tilde
|
||||
_addEntity( "Oacute", chr( 211 ) ); // capital O, acute accent
|
||||
_addEntity( "Ocirc", chr( 212 ) ); // capital O, circumflex accent
|
||||
_addEntity( "Ograve", chr( 210 ) ); // capital O, grave accent
|
||||
_addEntity( "Oslash", chr( 216 ) ); // capital O, slash
|
||||
_addEntity( "Otilde", chr( 213 ) ); // capital O, tilde
|
||||
_addEntity( "Ouml", chr( 214 ) ); // capital O, dieresis or umlaut mark
|
||||
_addEntity( "THORN", chr( 222 ) ); // capital THORN, Icelandic
|
||||
_addEntity( "Uacute", chr( 218 ) ); // capital U, acute accent
|
||||
_addEntity( "Ucirc", chr( 219 ) ); // capital U, circumflex accent
|
||||
_addEntity( "Ugrave", chr( 217 ) ); // capital U, grave accent
|
||||
_addEntity( "Uuml", chr( 220 ) ); // capital U, dieresis or umlaut mark
|
||||
_addEntity( "Yacute", chr( 221 ) ); // capital Y, acute accent
|
||||
_addEntity( "aacute", chr( 225 ) ); // small a, acute accent
|
||||
_addEntity( "acirc", chr( 226 ) ); // small a, circumflex accent
|
||||
_addEntity( "aelig", chr( 230 ) ); // small ae diphthong (ligature)
|
||||
_addEntity( "agrave", chr( 224 ) ); // small a, grave accent
|
||||
_addEntity( "aring", chr( 229 ) ); // small a, ring
|
||||
_addEntity( "atilde", chr( 227 ) ); // small a, tilde
|
||||
_addEntity( "auml", chr( 228 ) ); // small a, dieresis or umlaut mark
|
||||
_addEntity( "ccedil", chr( 231 ) ); // small c, cedilla
|
||||
_addEntity( "eacute", chr( 233 ) ); // small e, acute accent
|
||||
_addEntity( "ecirc", chr( 234 ) ); // small e, circumflex accent
|
||||
_addEntity( "egrave", chr( 232 ) ); // small e, grave accent
|
||||
_addEntity( "eth", chr( 240 ) ); // small eth, Icelandic
|
||||
_addEntity( "euml", chr( 235 ) ); // small e, dieresis or umlaut mark
|
||||
_addEntity( "iacute", chr( 237 ) ); // small i, acute accent
|
||||
_addEntity( "icirc", chr( 238 ) ); // small i, circumflex accent
|
||||
_addEntity( "igrave", chr( 236 ) ); // small i, grave accent
|
||||
_addEntity( "iuml", chr( 239 ) ); // small i, dieresis or umlaut mark
|
||||
_addEntity( "ntilde", chr( 241 ) ); // small n, tilde
|
||||
_addEntity( "oacute", chr( 243 ) ); // small o, acute accent
|
||||
_addEntity( "ocirc", chr( 244 ) ); // small o, circumflex accent
|
||||
_addEntity( "ograve", chr( 242 ) ); // small o, grave accent
|
||||
_addEntity( "oslash", chr( 248 ) ); // small o, slash
|
||||
_addEntity( "otilde", chr( 245 ) ); // small o, tilde
|
||||
_addEntity( "ouml", chr( 246 ) ); // small o, dieresis or umlaut mark
|
||||
_addEntity( "szlig", chr( 223 ) ); // small sharp s, German (sz ligature)
|
||||
_addEntity( "thorn", chr( 254 ) ); // small thorn, Icelandic
|
||||
_addEntity( "uacute", chr( 250 ) ); // small u, acute accent
|
||||
_addEntity( "ucirc", chr( 251 ) ); // small u, circumflex accent
|
||||
_addEntity( "ugrave", chr( 249 ) ); // small u, grave accent
|
||||
_addEntity( "uuml", chr( 252 ) ); // small u, dieresis or umlaut mark
|
||||
_addEntity( "yacute", chr( 253 ) ); // small y, acute accent
|
||||
_addEntity( "yuml", chr( 255 ) ); // small y, dieresis or umlaut mark
|
||||
_addEntity( "copy", chr( 169 ) ); // copyright sign
|
||||
_addEntity( "reg", chr( 174 ) ); // registered sign
|
||||
_addEntity( "nbsp", chr( 160 ) ); // non breaking space
|
||||
_addEntity( "iexcl", chr( 161 ) );
|
||||
_addEntity( "cent", chr( 162 ) );
|
||||
_addEntity( "pound", chr( 163 ) );
|
||||
_addEntity( "curren", chr( 164 ) );
|
||||
_addEntity( "yen", chr( 165 ) );
|
||||
_addEntity( "brvbar", chr( 166 ) );
|
||||
_addEntity( "sect", chr( 167 ) );
|
||||
_addEntity( "uml", chr( 168 ) );
|
||||
_addEntity( "ordf", chr( 170 ) );
|
||||
_addEntity( "laquo", chr( 171 ) );
|
||||
_addEntity( "not", chr( 172 ) );
|
||||
_addEntity( "shy", chr( 173 ) );
|
||||
_addEntity( "macr", chr( 175 ) );
|
||||
_addEntity( "deg", chr( 176 ) );
|
||||
_addEntity( "plusmn", chr( 177 ) );
|
||||
_addEntity( "sup1", chr( 185 ) );
|
||||
_addEntity( "sup2", chr( 178 ) );
|
||||
_addEntity( "sup3", chr( 179 ) );
|
||||
_addEntity( "acute", chr( 180 ) );
|
||||
_addEntity( "micro", chr( 181 ) );
|
||||
_addEntity( "para", chr( 182 ) );
|
||||
_addEntity( "middot", chr( 183 ) );
|
||||
_addEntity( "cedil", chr( 184 ) );
|
||||
_addEntity( "ordm", chr( 186 ) );
|
||||
_addEntity( "raquo", chr( 187 ) );
|
||||
_addEntity( "frac14", chr( 188 ) );
|
||||
_addEntity( "frac12", chr( 189 ) );
|
||||
_addEntity( "frac34", chr( 190 ) );
|
||||
_addEntity( "iquest", chr( 191 ) );
|
||||
_addEntity( "times", chr( 215 ) );
|
||||
|
||||
}
|
||||
|
||||
private static void init2(){
|
||||
_addEntity( "divide", chr( 247 ) );
|
||||
_addEntity( "OElig", chr( 338 ) );
|
||||
_addEntity( "oelig", chr( 339 ) );
|
||||
_addEntity( "Scaron", chr( 352 ) );
|
||||
_addEntity( "scaron", chr( 353 ) );
|
||||
_addEntity( "Yuml", chr( 376 ) );
|
||||
_addEntity( "fnof", chr( 402 ) );
|
||||
_addEntity( "circ", chr( 710 ) );
|
||||
_addEntity( "tilde", chr( 732 ) );
|
||||
_addEntity( "Alpha", chr( 913 ) );
|
||||
_addEntity( "Beta", chr( 914 ) );
|
||||
_addEntity( "Gamma", chr( 915 ) );
|
||||
_addEntity( "Delta", chr( 916 ) );
|
||||
_addEntity( "Epsilon", chr( 917 ) );
|
||||
_addEntity( "Zeta", chr( 918 ) );
|
||||
_addEntity( "Eta", chr( 919 ) );
|
||||
_addEntity( "Theta", chr( 920 ) );
|
||||
_addEntity( "Iota", chr( 921 ) );
|
||||
_addEntity( "Kappa", chr( 922 ) );
|
||||
_addEntity( "Lambda", chr( 923 ) );
|
||||
_addEntity( "Mu", chr( 924 ) );
|
||||
_addEntity( "Nu", chr( 925 ) );
|
||||
_addEntity( "Xi", chr( 926 ) );
|
||||
_addEntity( "Omicron", chr( 927 ) );
|
||||
_addEntity( "Pi", chr( 928 ) );
|
||||
_addEntity( "Rho", chr( 929 ) );
|
||||
_addEntity( "Sigma", chr( 931 ) );
|
||||
_addEntity( "Tau", chr( 932 ) );
|
||||
_addEntity( "Upsilon", chr( 933 ) );
|
||||
_addEntity( "Phi", chr( 934 ) );
|
||||
_addEntity( "Chi", chr( 935 ) );
|
||||
_addEntity( "Psi", chr( 936 ) );
|
||||
_addEntity( "Omega", chr( 937 ) );
|
||||
_addEntity( "alpha", chr( 945 ) );
|
||||
_addEntity( "beta", chr( 946 ) );
|
||||
_addEntity( "gamma", chr( 947 ) );
|
||||
_addEntity( "delta", chr( 948 ) );
|
||||
_addEntity( "epsilon", chr( 949 ) );
|
||||
_addEntity( "zeta", chr( 950 ) );
|
||||
_addEntity( "eta", chr( 951 ) );
|
||||
_addEntity( "theta", chr( 952 ) );
|
||||
_addEntity( "iota", chr( 953 ) );
|
||||
_addEntity( "kappa", chr( 954 ) );
|
||||
_addEntity( "lambda", chr( 955 ) );
|
||||
_addEntity( "mu", chr( 956 ) );
|
||||
_addEntity( "nu", chr( 957 ) );
|
||||
_addEntity( "xi", chr( 958 ) );
|
||||
_addEntity( "omicron", chr( 959 ) );
|
||||
_addEntity( "pi", chr( 960 ) );
|
||||
_addEntity( "rho", chr( 961 ) );
|
||||
_addEntity( "sigmaf", chr( 962 ) );
|
||||
_addEntity( "sigma", chr( 963 ) );
|
||||
_addEntity( "tau", chr( 964 ) );
|
||||
_addEntity( "upsilon", chr( 965 ) );
|
||||
_addEntity( "phi", chr( 966 ) );
|
||||
_addEntity( "chi", chr( 967 ) );
|
||||
_addEntity( "psi", chr( 968 ) );
|
||||
_addEntity( "omega", chr( 969 ) );
|
||||
_addEntity( "thetasym", chr( 977 ) );
|
||||
_addEntity( "upsih", chr( 978 ) );
|
||||
_addEntity( "piv", chr( 982 ) );
|
||||
_addEntity( "ensp", chr( 8194 ) );
|
||||
_addEntity( "emsp", chr( 8195 ) );
|
||||
_addEntity( "thinsp", chr( 8201 ) );
|
||||
_addEntity( "zwnj", chr( 8204 ) );
|
||||
_addEntity( "zwj", chr( 8205 ) );
|
||||
_addEntity( "lrm", chr( 8206 ) );
|
||||
_addEntity( "rlm", chr( 8207 ) );
|
||||
_addEntity( "ndash", chr( 8211 ) );
|
||||
_addEntity( "mdash", chr( 8212 ) );
|
||||
_addEntity( "lsquo", chr( 8216 ) );
|
||||
_addEntity( "rsquo", chr( 8217 ) );
|
||||
_addEntity( "sbquo", chr( 8218 ) );
|
||||
_addEntity( "ldquo", chr( 8220 ) );
|
||||
_addEntity( "rdquo", chr( 8221 ) );
|
||||
_addEntity( "bdquo", chr( 8222 ) );
|
||||
_addEntity( "dagger", chr( 8224 ) );
|
||||
_addEntity( "Dagger", chr( 8225 ) );
|
||||
_addEntity( "bull", chr( 8226 ) );
|
||||
_addEntity( "hellip", chr( 8230 ) );
|
||||
_addEntity( "permil", chr( 8240 ) );
|
||||
_addEntity( "prime", chr( 8242 ) );
|
||||
_addEntity( "Prime", chr( 8243 ) );
|
||||
_addEntity( "lsaquo", chr( 8249 ) );
|
||||
_addEntity( "rsaquo", chr( 8250 ) );
|
||||
_addEntity( "oline", chr( 8254 ) );
|
||||
_addEntity( "frasl", chr( 8260 ) );
|
||||
_addEntity( "euro", chr( 8364 ) );
|
||||
_addEntity( "image", chr( 8465 ) );
|
||||
_addEntity( "weierp", chr( 8472 ) );
|
||||
_addEntity( "real", chr( 8476 ) );
|
||||
_addEntity( "trade", chr( 8482 ) );
|
||||
_addEntity( "alefsym", chr( 8501 ) );
|
||||
_addEntity( "larr", chr( 8592 ) );
|
||||
_addEntity( "uarr", chr( 8593 ) );
|
||||
_addEntity( "rarr", chr( 8594 ) );
|
||||
_addEntity( "darr", chr( 8595 ) );
|
||||
_addEntity( "harr", chr( 8596 ) );
|
||||
_addEntity( "crarr", chr( 8629 ) );
|
||||
_addEntity( "lArr", chr( 8656 ) );
|
||||
|
||||
}
|
||||
|
||||
private static void init3(){
|
||||
_addEntity( "uArr", chr( 8657 ) );
|
||||
_addEntity( "rArr", chr( 8658 ) );
|
||||
_addEntity( "dArr", chr( 8659 ) );
|
||||
_addEntity( "hArr", chr( 8660 ) );
|
||||
_addEntity( "forall", chr( 8704 ) );
|
||||
_addEntity( "part", chr( 8706 ) );
|
||||
_addEntity( "exist", chr( 8707 ) );
|
||||
_addEntity( "empty", chr( 8709 ) );
|
||||
_addEntity( "nabla", chr( 8711 ) );
|
||||
_addEntity( "isin", chr( 8712 ) );
|
||||
_addEntity( "notin", chr( 8713 ) );
|
||||
_addEntity( "ni", chr( 8715 ) );
|
||||
_addEntity( "prod", chr( 8719 ) );
|
||||
_addEntity( "sum", chr( 8721 ) );
|
||||
_addEntity( "minus", chr( 8722 ) );
|
||||
_addEntity( "lowast", chr( 8727 ) );
|
||||
_addEntity( "radic", chr( 8730 ) );
|
||||
_addEntity( "prop", chr( 8733 ) );
|
||||
_addEntity( "infin", chr( 8734 ) );
|
||||
_addEntity( "ang", chr( 8736 ) );
|
||||
_addEntity( "and", chr( 8743 ) );
|
||||
_addEntity( "or", chr( 8744 ) );
|
||||
_addEntity( "cap", chr( 8745 ) );
|
||||
_addEntity( "cup", chr( 8746 ) );
|
||||
_addEntity( "int", chr( 8747 ) );
|
||||
_addEntity( "there4", chr( 8756 ) );
|
||||
_addEntity( "sim", chr( 8764 ) );
|
||||
_addEntity( "cong", chr( 8773 ) );
|
||||
_addEntity( "asymp", chr( 8776 ) );
|
||||
_addEntity( "ne", chr( 8800 ) );
|
||||
_addEntity( "equiv", chr( 8801 ) );
|
||||
_addEntity( "le", chr( 8804 ) );
|
||||
_addEntity( "ge", chr( 8805 ) );
|
||||
_addEntity( "sub", chr( 8834 ) );
|
||||
_addEntity( "sup", chr( 8835 ) );
|
||||
_addEntity( "nsub", chr( 8836 ) );
|
||||
_addEntity( "sube", chr( 8838 ) );
|
||||
_addEntity( "supe", chr( 8839 ) );
|
||||
_addEntity( "oplus", chr( 8853 ) );
|
||||
_addEntity( "otimes", chr( 8855 ) );
|
||||
_addEntity( "perp", chr( 8869 ) );
|
||||
_addEntity( "sdot", chr( 8901 ) );
|
||||
_addEntity( "lceil", chr( 8968 ) );
|
||||
_addEntity( "rceil", chr( 8969 ) );
|
||||
_addEntity( "lfloor", chr( 8970 ) );
|
||||
_addEntity( "rfloor", chr( 8971 ) );
|
||||
_addEntity( "lang", chr( 9001 ) );
|
||||
_addEntity( "rang", chr( 9002 ) );
|
||||
_addEntity( "loz", chr( 9674 ) );
|
||||
_addEntity( "spades", chr( 9824 ) );
|
||||
_addEntity( "clubs", chr( 9827 ) );
|
||||
_addEntity( "hearts", chr( 9829 ) );
|
||||
_addEntity( "diams", chr( 9830 ) );
|
||||
|
||||
}
|
||||
|
||||
static{
|
||||
init1();
|
||||
init2();
|
||||
init3();
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 458 B |
After Width: | Height: | Size: 372 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 561 B |
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 144 B |
After Width: | Height: | Size: 309 B |
After Width: | Height: | Size: 317 B |
After Width: | Height: | Size: 257 B |
After Width: | Height: | Size: 579 B |
After Width: | Height: | Size: 403 B |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 123 B |
After Width: | Height: | Size: 193 B |
After Width: | Height: | Size: 567 B |
After Width: | Height: | Size: 406 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 599 B |
After Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 148 B |
After Width: | Height: | Size: 290 B |
After Width: | Height: | Size: 930 B |
After Width: | Height: | Size: 663 B |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 436 B |
After Width: | Height: | Size: 207 B |
After Width: | Height: | Size: 519 B |
|
@ -17,19 +17,8 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay"/>
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
<!-- ここに広告いれたい -->
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -60,13 +49,21 @@
|
|||
/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:id="@+id/fabToot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:srcCompat="@android:drawable/ic_dialog_email"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_toot"
|
||||
/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fabMenu"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:srcCompat="@drawable/ic_menu"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnAccount"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnAttachment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/btn_attachment"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCharCount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnPost"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/btn_post"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llAttachment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia2"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia3"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia4"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbContentWarning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/content_warning"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etContentWarning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/content_warning_hint"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/status"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textMultiLine"
|
||||
android:hint="@string/content_hint"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -18,7 +18,7 @@
|
|||
android:labelFor="@+id/etInstance"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/etInstance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<CheckedTextView
|
||||
android:id="@android:id/text1"
|
||||
style="?android:attr/spinnerDropDownItemStyle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:ellipsize="marquee"
|
||||
/>
|
|
@ -0,0 +1,110 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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:orientation="vertical"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/tvCreated"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:textColor="#888888"
|
||||
android:textSize="12sp"
|
||||
tools:text="xxxx-xx-xx xx:xx:xx"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#40ffffff"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp"
|
||||
>
|
||||
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivAvatar"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="#888"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDisplayName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center"
|
||||
android:textSize="20dp"
|
||||
tools:text="ディスプレイネームディスプレイネームディスプレイネーム"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAcct"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
tools:text="\@fugahogehogera\@jugemujyugemugokounosurikire.jp"
|
||||
android:textColor="@color/colorLink"
|
||||
/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvNote"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
tools:text="説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 説明文 "
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnStatusCount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="statuses\n124"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnFollowing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="following\n9999"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnFollowers"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="followers\n9999"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -7,6 +7,7 @@
|
|||
android:orientation="vertical"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -41,7 +42,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:textColor="#888888"
|
||||
android:textSize="12dp"
|
||||
android:textSize="12sp"
|
||||
tools:text="2017-04-16 09:37:14"
|
||||
/>
|
||||
|
||||
|
@ -64,18 +65,16 @@
|
|||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/ivFollow"
|
||||
android:background="#888"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:scaleType="fitEnd"
|
||||
/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -95,7 +94,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#888888"
|
||||
android:textSize="12dp"
|
||||
android:textSize="12sp"
|
||||
tools:text="aaaaaaaaaaaaaaaa"
|
||||
/>
|
||||
|
||||
|
@ -116,13 +115,12 @@
|
|||
android:id="@+id/llStatus"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivThumbnail"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="#888"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
|
@ -140,7 +138,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:textColor="#888888"
|
||||
android:textSize="12dp"
|
||||
android:textSize="12sp"
|
||||
tools:text="2017-04-16 09:37:14"
|
||||
/>
|
||||
|
||||
|
@ -152,6 +150,28 @@
|
|||
tools:text="Displayname @username"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:id="@+id/llContentWarning"
|
||||
>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
tools:text="見る"
|
||||
android:id="@+id/btnContentWarning"
|
||||
android:minWidth="32dp"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/tvContentWarning"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/tvContent"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -159,15 +179,75 @@
|
|||
android:layout_marginTop="8dp"
|
||||
tools:text="Contents\nContents"
|
||||
/>
|
||||
<!-- TODO: make MultipleImageView -->
|
||||
<ImageView
|
||||
android:id="@+id/ivMedia"
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="#f88"
|
||||
android:contentDescription="@string/media_attachment"
|
||||
android:scaleType="centerCrop"/>
|
||||
android:id="@+id/flMedia"
|
||||
>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
<com.android.volley.toolbox.NetworkImageView
|
||||
android:id="@+id/ivMedia4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/thumbnail"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@null"
|
||||
android:src="@drawable/btn_close"
|
||||
android:contentDescription="@string/hide"
|
||||
android:id="@+id/btnHideMedia"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#000"
|
||||
android:textColor="#fff"
|
||||
android:text="@string/tap_to_show"
|
||||
android:id="@+id/btnShowMedia"
|
||||
android:gravity="center"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -184,20 +264,20 @@
|
|||
android:src="@drawable/btn_reply"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
<Button
|
||||
android:id="@+id/btnBoost"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/boost"
|
||||
android:src="@drawable/btn_boost"
|
||||
android:drawablePadding="4dp"
|
||||
android:minWidth="32dp"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
<Button
|
||||
android:id="@+id/btnFavourite"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/favourite"
|
||||
android:src="@drawable/btn_favourite"
|
||||
android:drawablePadding="4dp"
|
||||
android:minWidth="32dp"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
|
|
|
@ -9,39 +9,57 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="12dp"
|
||||
|
||||
android:background="#ddd"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvColumnName"
|
||||
android:layout_width="0dp"
|
||||
android:id="@+id/tvColumnContext"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
tools:text="tvColumnName"
|
||||
android:gravity="end"
|
||||
android:textColor="#888"
|
||||
android:textSize="12sp"
|
||||
tools:text="tvColumnContext"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnColumnReload"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/reload"
|
||||
android:src="@drawable/btn_refresh"
|
||||
android:layout_gravity="center_vertical"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnColumnClose"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/close_column"
|
||||
android:src="@drawable/black_close"
|
||||
android:layout_gravity="center_vertical"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/tvColumnName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
tools:text="tvColumnName"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnColumnReload"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/reload"
|
||||
android:src="@drawable/btn_refresh"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnColumnClose"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/close_column"
|
||||
android:src="@drawable/black_close"
|
||||
/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
|
@ -58,11 +76,11 @@
|
|||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingBottom="64dp"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:fadeScrollbars="false"
|
||||
android:paddingBottom="64dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingStart="12dp"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -3,4 +3,7 @@
|
|||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
|
||||
<color name="colorLink">#00a2ff</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<string name="register_app_to_server">registering this app to %1$s…</string>
|
||||
<string name="request_access_token">request access token…</string>
|
||||
<string name="request_api">get %1$s…</string>
|
||||
<string name="column_empty">please add column from left-top menu button</string>
|
||||
<string name="column_empty">please add column from left-bottom menu button</string>
|
||||
<string name="home">home</string>
|
||||
<string name="local_timeline">local timeline</string>
|
||||
<string name="federate_timeline">federated timeline</string>
|
||||
|
@ -32,7 +32,7 @@
|
|||
<string name="show_home">add home</string>
|
||||
<string name="account_pick">select account</string>
|
||||
<string name="local_tl">local timeline</string>
|
||||
<string name="accout_confirmed">account confirmed.</string>
|
||||
<string name="account_confirmed">account confirmed.</string>
|
||||
<string name="reply">reply</string>
|
||||
<string name="boost">boost</string>
|
||||
<string name="favourite">favourite</string>
|
||||
|
@ -55,4 +55,22 @@
|
|||
<string name="follow">follow</string>
|
||||
<string name="favourited_by">favourited by %1$s</string>
|
||||
<string name="add_column">add column</string>
|
||||
<string name="profile_page">profile\npage</string>
|
||||
<string name="following">following</string>
|
||||
<string name="followers">followers</string>
|
||||
<string name="statuses">statuses</string>
|
||||
<string name="hide">hide</string>
|
||||
<string name="nsfw">NSFW</string>
|
||||
<string name="show_media">NSFW\n(tap to show)</string>
|
||||
<string name="tap_to_show">tap to show</string>
|
||||
<string name="show">show</string>
|
||||
<string name="act_post">posting Toot</string>
|
||||
<string name="content_warning">content warning</string>
|
||||
<string name="content">content</string>
|
||||
<string name="please_add_account">missng account. please add account before posting.</string>
|
||||
<string name="not_selected">(not selected)</string>
|
||||
<string name="content_warning_hint">please input text for content warning.</string>
|
||||
<string name="content_hint">please input your status</string>
|
||||
<string name="status">status</string>
|
||||
<string name="list_empty">no items in list</string>
|
||||
</resources>
|
||||
|
|