migrating to kotlin

This commit is contained in:
Mariotaku Lee 2016-07-06 21:21:34 +08:00
parent f63282f039
commit 8047612281
147 changed files with 2196 additions and 2432 deletions

View File

@ -62,7 +62,7 @@ public class NyanDaydreamService extends DreamService implements NyanConstants,
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
if (KEY_LIVE_WALLPAPER_SCALE.equals(key)) {
updateView();
}

View File

@ -84,7 +84,7 @@ public class NyanWallpaperService extends WallpaperService implements NyanConsta
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
if (KEY_LIVE_WALLPAPER_SCALE.equals(key)) {
updateSurface();
}

View File

@ -65,12 +65,10 @@ android {
resValue("bool", "debug", "false")
}
}
sourceSets {
main {
res.srcDirs += project.files("src/$name/res-localized")
res.srcDirs += project.files("src/$name/res-svg2png")
java.srcDirs += 'src/main/kotlin'
}
sourceSets.each {
it.res.srcDirs += project.files("src/${it.name}/res-localized")
it.res.srcDirs += project.files("src/${it.name}/res-svg2png")
it.java.srcDirs += "src/${it.name}/kotlin"
}
testOptions {
unitTests.returnDefaultValues = true

View File

@ -17,30 +17,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
package org.mariotaku.twidere.util
import android.support.v4.app.Fragment;
import android.support.v4.app.Fragment
import org.mariotaku.twidere.model.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableCardEntity
/**
* Created by mariotaku on 15/1/1.
*/
public final class TwitterCardFragmentFactoryImpl extends TwitterCardFragmentFactory {
class TwitterCardFragmentFactoryImpl : TwitterCardFragmentFactory() {
@Override
public Fragment createAnimatedGifFragment(ParcelableCardEntity card) {
return null;
override fun createAnimatedGifFragment(card: ParcelableCardEntity): Fragment? {
return null
}
@Override
public Fragment createAudioFragment(ParcelableCardEntity card) {
return null;
override fun createAudioFragment(card: ParcelableCardEntity): Fragment? {
return null
}
@Override
public Fragment createPlayerFragment(ParcelableCardEntity card) {
return null;
override fun createPlayerFragment(card: ParcelableCardEntity): Fragment? {
return null
}
}

View File

@ -1,78 +0,0 @@
package org.mariotaku.twidere.activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
/**
* Created by mariotaku on 16/5/14.
*/
public class PlusServiceGoogleSignInActivity extends BasePlusServiceSignInActivity implements
GoogleApiClient.OnConnectionFailedListener {
private static final int REQUEST_GOOGLE_SIGN_IN = 101;
private GoogleApiClient mGoogleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(GOOGLE_APIS_SERVER_CLIENT_ID)
.build();
// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified by gso.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
signInWithGoogle();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == REQUEST_GOOGLE_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
private void signInWithGoogle() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, REQUEST_GOOGLE_SIGN_IN);
}
private void handleSignInResult(GoogleSignInResult result) {
Log.d(LOGTAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// TODO Signed in successfully, show authenticated UI.
GoogleSignInAccount acct = result.getSignInAccount();
acct.getIdToken();
Log.d(LOGTAG, "sign in name:" + acct.getDisplayName());
} else {
// TODO Signed out, show unauthenticated UI.
}
finish();
}
}

View File

@ -1,162 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.iface.IBaseFragment;
import org.mariotaku.twidere.fragment.iface.IMapFragment;
public class GoogleMapFragment extends SupportMapFragment implements Constants, IMapFragment, IBaseFragment {
private GoogleMap mMapView;
private ActionHelper mActionHelper = new ActionHelper(this);
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
final Bundle args = getArguments();
if (args == null || !args.containsKey(EXTRA_LATITUDE) || !args.containsKey(EXTRA_LONGITUDE))
return;
final double lat = args.getDouble(EXTRA_LATITUDE, 0.0), lng = args.getDouble(EXTRA_LONGITUDE, 0.0);
getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
mMapView = googleMap;
final MarkerOptions marker = new MarkerOptions();
marker.position(new LatLng(lat, lng));
mMapView.addMarker(marker);
center(false);
}
});
}
@Override
public void onPause() {
mActionHelper.dispatchOnPause();
super.onPause();
}
@Override
public void onResume() {
super.onResume();
mActionHelper.dispatchOnResumeFragments();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_google_maps_viewer, menu);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
requestFitSystemWindows();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.center: {
center();
break;
}
}
return true;
}
@Override
public void center() {
center(true);
}
public void center(final boolean animate) {
final Bundle args = getArguments();
if (mMapView == null || args == null || !args.containsKey(EXTRA_LATITUDE) || !args.containsKey(EXTRA_LONGITUDE))
return;
final double lat = args.getDouble(EXTRA_LATITUDE, 0.0), lng = args.getDouble(EXTRA_LONGITUDE, 0.0);
final CameraUpdate c = CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 12);
if (animate) {
mMapView.animateCamera(c);
} else {
mMapView.moveCamera(c);
}
}
@Override
public Bundle getExtraConfiguration() {
return null;
}
@Override
public int getTabPosition() {
return 0;
}
@Override
public void requestFitSystemWindows() {
final Activity activity = getActivity();
final Fragment parentFragment = getParentFragment();
final IBaseFragment.SystemWindowsInsetsCallback callback;
if (parentFragment instanceof IBaseFragment.SystemWindowsInsetsCallback) {
callback = (IBaseFragment.SystemWindowsInsetsCallback) parentFragment;
} else if (activity instanceof IBaseFragment.SystemWindowsInsetsCallback) {
callback = (IBaseFragment.SystemWindowsInsetsCallback) activity;
} else {
return;
}
final Rect insets = new Rect();
if (callback.getSystemWindowsInsets(insets)) {
fitSystemWindows(insets);
}
}
@Override
public void executeAfterFragmentResumed(Action action) {
mActionHelper.executeAfterFragmentResumed(action);
}
protected void fitSystemWindows(Rect insets) {
final View view = getView();
if (view != null) {
view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
}
}
}

View File

@ -1,140 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.iface.IMapFragment;
import org.mariotaku.twidere.util.webkit.DefaultWebViewClient;
public class WebMapFragment extends BaseSupportWebViewFragment implements IMapFragment {
private static final String MAPVIEW_URI = "file:///android_asset/mapview.html";
private double latitude, longitude;
@Override
public void center() {
final WebView webview = getWebView();
webview.loadUrl("javascript:center();");
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.center: {
center();
break;
}
}
return true;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_google_maps_viewer, menu);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
getLocation();
setupWebView();
}
/**
* The Location Manager manages location providers. This code searches for
* the best provider of data (GPS, WiFi/cell phone tower lookup, some other
* mechanism) and finds the last known location.
*/
private void getLocation() {
final Bundle bundle = getArguments();
if (bundle != null) {
latitude = bundle.getDouble(EXTRA_LATITUDE, 0.0);
longitude = bundle.getDouble(EXTRA_LONGITUDE, 0.0);
}
}
/**
* Sets up the WebView object and loads the URL of the page *
*/
private void setupWebView() {
final WebView webview = getWebView();
webview.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webview.setWebViewClient(new MapWebViewClient(getActivity()));
webview.loadUrl(MAPVIEW_URI);
final WebSettings settings = webview.getSettings();
settings.setBuiltInZoomControls(false);
/** Allows JavaScript calls to access application resources **/
webview.addJavascriptInterface(new MapJavaScriptInterface(), "android");
}
/**
* Sets up the interface for getting access to Latitude and Longitude data
* from device
*/
class MapJavaScriptInterface {
@JavascriptInterface
public double getLatitude() {
return latitude;
}
@JavascriptInterface
public double getLongitude() {
return longitude;
}
}
class MapWebViewClient extends DefaultWebViewClient {
public MapWebViewClient(final Activity activity) {
super(activity);
}
@Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
final Uri uri = Uri.parse(url);
if (uri.getScheme().equals(Uri.parse(MAPVIEW_URI).getScheme())) return false;
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
}

View File

@ -1,61 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.app.Application;
import android.os.Build;
import android.support.annotation.NonNull;
import com.crashlytics.android.Crashlytics;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import io.fabric.sdk.android.Fabric;
/**
* Created by mariotaku on 15/7/8.
*/
public class TwidereBugReporter extends BugReporter implements Constants {
@Override
protected void logImpl(int priority, String tag, String msg) {
Crashlytics.log(priority, tag, msg);
}
@Override
protected void logExceptionImpl(@NonNull final Throwable throwable) {
Crashlytics.logException(throwable);
}
@Override
protected void initImpl(final Application application) {
Fabric.with(application, new Crashlytics());
Crashlytics.setBool("debug", BuildConfig.DEBUG);
Crashlytics.setString("build.brand", Build.BRAND);
Crashlytics.setString("build.device", Build.DEVICE);
Crashlytics.setString("build.display", Build.DISPLAY);
Crashlytics.setString("build.hardware", Build.HARDWARE);
Crashlytics.setString("build.manufacturer", Build.MANUFACTURER);
Crashlytics.setString("build.model", Build.MODEL);
Crashlytics.setString("build.product", Build.PRODUCT);
}
}

View File

@ -1,85 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.net.Uri;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerSupportFragment;
import org.mariotaku.twidere.model.ParcelableCardEntity;
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils;
/**
* Created by mariotaku on 15/1/1.
*/
public final class TwitterCardFragmentFactoryImpl extends TwitterCardFragmentFactory {
private static final String YOUTUBE_DATA_API_KEY = "AIzaSyCVdCIMFFxdNqHnCPrJ9yKUzoTfs8jhYGc";
@Override
public Fragment createAnimatedGifFragment(ParcelableCardEntity card) {
return null;
}
@Override
public Fragment createAudioFragment(ParcelableCardEntity card) {
return null;
}
@Override
public Fragment createPlayerFragment(ParcelableCardEntity card) {
if (Boolean.parseBoolean("true")) return null;
final String appUrlResolved = ParcelableCardEntityUtils.getString(card, "app_url_resolved");
final String domain = ParcelableCardEntityUtils.getString(card, "domain");
if (domain != null && appUrlResolved != null) {
final Uri uri = Uri.parse(appUrlResolved);
final String paramV = uri.getQueryParameter("v");
if ("www.youtube.com".equals(domain) && paramV != null) {
final YouTubePlayerSupportFragment fragment = YouTubePlayerSupportFragment.newInstance();
fragment.initialize(YOUTUBE_DATA_API_KEY, new YouTubePlayer.OnInitializedListener() {
@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) {
if (!wasRestored) {
player.cueVideo(paramV);
}
}
@Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult errorReason) {
final FragmentActivity activity = fragment.getActivity();
if (activity == null) return;
// if (errorReason.isUserRecoverableError()) {
// errorReason.getErrorDialog(activity, RECOVERY_DIALOG_REQUEST).show();
// } else {
// Toast.makeText(activity, errorReason.toString(), Toast.LENGTH_LONG).show();
// }
}
});
return fragment;
}
}
return null;
}
}

View File

@ -0,0 +1,68 @@
package org.mariotaku.twidere.activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import com.google.android.gms.auth.api.Auth
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.auth.api.signin.GoogleSignInResult
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
/**
* Created by mariotaku on 16/5/14.
*/
class PlusServiceGoogleSignInActivity : BasePlusServiceSignInActivity(), GoogleApiClient.OnConnectionFailedListener {
private var mGoogleApiClient: GoogleApiClient? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail().requestIdToken(GOOGLE_APIS_SERVER_CLIENT_ID).build()
// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified by gso.
mGoogleApiClient = GoogleApiClient.Builder(this).enableAutoManage(this, this).addApi(Auth.GOOGLE_SIGN_IN_API, gso).build()
signInWithGoogle()
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == REQUEST_GOOGLE_SIGN_IN) {
val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
handleSignInResult(result)
}
}
override fun onConnectionFailed(connectionResult: ConnectionResult) {
}
private fun signInWithGoogle() {
val signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient)
startActivityForResult(signInIntent, REQUEST_GOOGLE_SIGN_IN)
}
private fun handleSignInResult(result: GoogleSignInResult) {
Log.d(LOGTAG, "handleSignInResult:" + result.isSuccess)
if (result.isSuccess) {
// TODO Signed in successfully, show authenticated UI.
val acct = result.signInAccount
acct!!.idToken
Log.d(LOGTAG, "sign in name:" + acct.displayName!!)
} else {
// TODO Signed out, show unauthenticated UI.
}
finish()
}
companion object {
private val REQUEST_GOOGLE_SIGN_IN = 101
}
}

View File

@ -0,0 +1,133 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.webkit.JavascriptInterface
import android.webkit.WebView
import org.mariotaku.twidere.Constants.EXTRA_LATITUDE
import org.mariotaku.twidere.Constants.EXTRA_LONGITUDE
import org.mariotaku.twidere.R
import org.mariotaku.twidere.fragment.iface.IMapFragment
import org.mariotaku.twidere.util.webkit.DefaultWebViewClient
class WebMapFragment : BaseSupportWebViewFragment(), IMapFragment {
private var latitude: Double = 0.toDouble()
private var longitude: Double = 0.toDouble()
override fun center() {
webView?.loadUrl("javascript:center();")
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.center -> {
center()
}
}
return true
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater!!.inflate(R.menu.menu_google_maps_viewer, menu)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
getLocation()
setupWebView()
}
/**
* The Location Manager manages location providers. This code searches for
* the best provider of data (GPS, WiFi/cell phone tower lookup, some other
* mechanism) and finds the last known location.
*/
private fun getLocation() {
val bundle = arguments
if (bundle != null) {
latitude = bundle.getDouble(EXTRA_LATITUDE, 0.0)
longitude = bundle.getDouble(EXTRA_LONGITUDE, 0.0)
}
}
/**
* Sets up the WebView object and loads the URL of the page *
*/
private fun setupWebView() {
val webView = webView!!
webView.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
webView.setWebViewClient(MapWebViewClient(activity))
webView.loadUrl(MAPVIEW_URI)
val settings = webView.settings
settings.builtInZoomControls = false
/** Allows JavaScript calls to access application resources */
webView.addJavascriptInterface(MapJavaScriptInterface(this), "android")
}
/**
* Sets up the interface for getting access to Latitude and Longitude data
* from device
*/
internal class MapJavaScriptInterface(val fragment: WebMapFragment) {
@JavascriptInterface
fun getLatitude(): Double {
return fragment.latitude
}
@JavascriptInterface
fun getLongitude(): Double {
return fragment.longitude
}
}
internal inner class MapWebViewClient(activity: Activity) : DefaultWebViewClient(activity) {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
val uri = Uri.parse(url)
if (uri.scheme == Uri.parse(MAPVIEW_URI).scheme) return false
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
return true
}
}
companion object {
private val MAPVIEW_URI = "file:///android_asset/mapview.html"
}
}

View File

@ -17,26 +17,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
package org.mariotaku.twidere.util
import android.content.Context;
import android.support.v4.app.Fragment;
import android.content.Context
import android.support.v4.app.Fragment
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import org.mariotaku.twidere.fragment.GoogleMapFragment;
import org.mariotaku.twidere.fragment.WebMapFragment;
import org.mariotaku.twidere.fragment.GoogleMapFragment
import org.mariotaku.twidere.fragment.WebMapFragment
/**
* Created by mariotaku on 15/4/27.
*/
public class MapFragmentFactoryImpl extends MapFragmentFactory {
@Override
public Fragment createMapFragment(Context context) {
class MapFragmentFactoryImpl : MapFragmentFactory() {
override fun createMapFragment(context: Context): Fragment? {
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS) {
return new GoogleMapFragment();
return GoogleMapFragment()
}
return new WebMapFragment();
return WebMapFragment()
}
}

View File

@ -0,0 +1,54 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util
import android.app.Application
import android.os.Build
import com.crashlytics.android.Crashlytics
import io.fabric.sdk.android.Fabric
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants
/**
* Created by mariotaku on 15/7/8.
*/
class TwidereBugReporter : BugReporter(), Constants {
override fun logImpl(priority: Int, tag: String, msg: String) {
Crashlytics.log(priority, tag, msg)
}
override fun logExceptionImpl(throwable: Throwable) {
Crashlytics.logException(throwable)
}
override fun initImpl(application: Application) {
Fabric.with(application, Crashlytics())
Crashlytics.setBool("debug", BuildConfig.DEBUG)
Crashlytics.setString("build.brand", Build.BRAND)
Crashlytics.setString("build.device", Build.DEVICE)
Crashlytics.setString("build.display", Build.DISPLAY)
Crashlytics.setString("build.hardware", Build.HARDWARE)
Crashlytics.setString("build.manufacturer", Build.MANUFACTURER)
Crashlytics.setString("build.model", Build.MODEL)
Crashlytics.setString("build.product", Build.PRODUCT)
}
}

View File

@ -0,0 +1,79 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util
import android.net.Uri
import android.support.v4.app.Fragment
import com.google.android.youtube.player.YouTubeInitializationResult
import com.google.android.youtube.player.YouTubePlayer
import com.google.android.youtube.player.YouTubePlayerSupportFragment
import org.mariotaku.twidere.model.ParcelableCardEntity
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils
/**
* Created by mariotaku on 15/1/1.
*/
class TwitterCardFragmentFactoryImpl : TwitterCardFragmentFactory() {
override fun createAnimatedGifFragment(card: ParcelableCardEntity): Fragment? {
return null
}
override fun createAudioFragment(card: ParcelableCardEntity): Fragment? {
return null
}
override fun createPlayerFragment(card: ParcelableCardEntity): Fragment? {
if (java.lang.Boolean.parseBoolean("true")) return null
val appUrlResolved = ParcelableCardEntityUtils.getString(card, "app_url_resolved")
val domain = ParcelableCardEntityUtils.getString(card, "domain")
if (domain != null && appUrlResolved != null) {
val uri = Uri.parse(appUrlResolved)
val paramV = uri.getQueryParameter("v")
if ("www.youtube.com" == domain && paramV != null) {
val fragment = YouTubePlayerSupportFragment.newInstance()
fragment.initialize(YOUTUBE_DATA_API_KEY, object : YouTubePlayer.OnInitializedListener {
override fun onInitializationSuccess(provider: YouTubePlayer.Provider, player: YouTubePlayer, wasRestored: Boolean) {
if (!wasRestored) {
player.cueVideo(paramV)
}
}
override fun onInitializationFailure(provider: YouTubePlayer.Provider, errorReason: YouTubeInitializationResult) {
val activity = fragment.activity ?: return
// if (errorReason.isUserRecoverableError()) {
// errorReason.getErrorDialog(activity, RECOVERY_DIALOG_REQUEST).show();
// } else {
// Toast.makeText(activity, errorReason.toString(), Toast.LENGTH_LONG).show();
// }
}
})
return fragment
}
}
return null
}
companion object {
private val YOUTUBE_DATA_API_KEY = "AIzaSyCVdCIMFFxdNqHnCPrJ9yKUzoTfs8jhYGc"
}
}

View File

@ -60,7 +60,7 @@ public class NyanActivity extends Activity implements OnLongClickListener, OnSha
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
if (KEY_LIVE_WALLPAPER_SCALE.equals(key)) {
updateSurface();
}

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
@ -178,7 +179,8 @@ public class AccountsAdapter extends SimpleDragSortCursorAdapter implements IBas
}
@Override
public Cursor swapCursor(final Cursor cursor) {
@Nullable
public Cursor swapCursor(@Nullable final Cursor cursor) {
if (cursor != null) {
mIndices = new ParcelableAccountCursorIndices(cursor);
}

View File

@ -156,7 +156,7 @@ public class ComposeAutoCompleteAdapter extends SimpleCursorAdapter implements C
@Override
@Nullable
public Cursor swapCursor(final Cursor cursor) {
public Cursor swapCursor(@Nullable final Cursor cursor) {
if (cursor != null) {
mTypeIdx = cursor.getColumnIndex(Suggestions.AutoComplete.TYPE);
mTitleIdx = cursor.getColumnIndex(Suggestions.AutoComplete.TITLE);

View File

@ -78,7 +78,7 @@ public class SourceAutoCompleteAdapter extends SimpleCursorAdapter {
@Override
@Nullable
public Cursor swapCursor(final Cursor cursor) {
public Cursor swapCursor(@Nullable final Cursor cursor) {
if (cursor != null) {
mSourceIdx = cursor.getColumnIndex(CachedStatuses.SOURCE);
}

View File

@ -42,7 +42,7 @@ public class TrendsAdapter extends SimpleCursorAdapter {
@Override
@Nullable
public Cursor swapCursor(Cursor c) {
public Cursor swapCursor(@Nullable Cursor c) {
if (c != null) {
mNameIdx = c.getColumnIndex(TwidereDataStore.CachedTrends.NAME);
}

View File

@ -137,7 +137,7 @@ public class UserAutoCompleteAdapter extends SimpleCursorAdapter {
@Override
@Nullable
public Cursor swapCursor(final Cursor cursor) {
public Cursor swapCursor(@Nullable final Cursor cursor) {
if (cursor != null) {
mIdIdx = cursor.getColumnIndex(CachedUsers.USER_KEY);
mNameIdx = cursor.getColumnIndex(CachedUsers.NAME);

View File

@ -1,55 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.os.Bundle;
import android.support.v7.preference.Preference;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableAccount;
public class AccountNotificationSettingsFragment extends BaseAccountPreferenceFragment {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Preference preference = findPreference(KEY_NOTIFICATION_LIGHT_COLOR);
final ParcelableAccount account = getAccount();
if (preference != null && account != null) {
preference.setDefaultValue(account.color);
}
}
@Override
protected int getPreferencesResource() {
return R.xml.preferences_account_notifications;
}
@Override
protected boolean getSwitchPreferenceDefault() {
return DEFAULT_NOTIFICATION;
}
@Override
protected String getSwitchPreferenceKey() {
return KEY_NOTIFICATION;
}
}

View File

@ -1,55 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.content.SharedPreferences;
import android.support.annotation.Nullable;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.Utils;
public class AccountRefreshSettingsFragment extends BaseAccountPreferenceFragment {
@Override
protected int getPreferencesResource() {
return R.xml.preferences_account_refresh;
}
@Override
protected boolean getSwitchPreferenceDefault() {
return DEFAULT_AUTO_REFRESH;
}
@Override
@Nullable
protected String getSwitchPreferenceKey() {
return null;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
final Activity activity = getActivity();
if (activity == null) return;
if (KEY_AUTO_REFRESH.equals(key)) {
Utils.startRefreshServiceIfNeeded(activity);
}
}
}

View File

@ -60,6 +60,14 @@ import org.mariotaku.twidere.util.collection.CompactHashSet;
import java.util.ArrayList;
import java.util.Set;
import static org.mariotaku.twidere.Constants.EXTRA_ALPHA_SLIDER;
import static org.mariotaku.twidere.Constants.EXTRA_COLOR;
import static org.mariotaku.twidere.Constants.EXTRA_ID;
import static org.mariotaku.twidere.Constants.INTENT_ACTION_TWITTER_LOGIN;
import static org.mariotaku.twidere.Constants.KEY_DEFAULT_ACCOUNT_KEY;
import static org.mariotaku.twidere.Constants.KEY_NEW_DOCUMENT_API;
import static org.mariotaku.twidere.Constants.REQUEST_SET_COLOR;
/**
* Created by mariotaku on 14/10/26.
*/
@ -295,7 +303,7 @@ public class AccountsManagerFragment extends BaseSupportFragment implements Load
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (KEY_DEFAULT_ACCOUNT_KEY.equals(key)) {
updateDefaultAccount();
}

View File

@ -1,129 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.annotation.Nullable;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableAccount;
public abstract class BaseAccountPreferenceFragment extends BasePreferenceFragment implements
OnCheckedChangeListener, OnSharedPreferenceChangeListener {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreatePreferences(Bundle bundle, String s) {
final PreferenceManager pm = getPreferenceManager();
final ParcelableAccount account = getArguments().getParcelable(EXTRA_ACCOUNT);
final String preferenceName = ACCOUNT_PREFERENCES_NAME_PREFIX
+ (account != null ? account.account_key : "unknown");
pm.setSharedPreferencesName(preferenceName);
addPreferencesFromResource(getPreferencesResource());
final SharedPreferences prefs = pm.getSharedPreferences();
prefs.registerOnSharedPreferenceChangeListener(this);
final Activity activity = getActivity();
final Intent intent = activity.getIntent();
if (account != null && intent.hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
final boolean nameFirst = prefs.getBoolean(KEY_NAME_FIRST, true);
final String name = mUserColorNameManager.getDisplayName(account.account_key,
account.name, account.screen_name, nameFirst);
activity.setTitle(name);
}
updatePreferenceScreen();
}
@Override
public void onDestroy() {
final PreferenceManager pm = getPreferenceManager();
final SharedPreferences prefs = pm.getSharedPreferences();
prefs.unregisterOnSharedPreferenceChangeListener(this);
super.onDestroy();
}
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
final SharedPreferences.Editor editor = prefs.edit();
if (prefs.getBoolean(getSwitchPreferenceKey(), getSwitchPreferenceDefault()) != isChecked) {
editor.putBoolean(getSwitchPreferenceKey(), isChecked);
editor.apply();
}
}
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
final String switchKey = getSwitchPreferenceKey();
if (!TextUtils.isEmpty(switchKey)) {
inflater.inflate(R.menu.menu_switch_preference, menu);
final View actionView = menu.findItem(R.id.toggle).getActionView();
final CompoundButton toggle = (CompoundButton) actionView.findViewById(android.R.id.toggle);
final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
toggle.setOnCheckedChangeListener(this);
toggle.setChecked(prefs.getBoolean(switchKey, getSwitchPreferenceDefault()));
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
if (key.equals(getSwitchPreferenceKey())) {
updatePreferenceScreen();
}
}
protected ParcelableAccount getAccount() {
final Bundle args = getArguments();
if (args == null) return null;
return args.getParcelable(EXTRA_ACCOUNT);
}
protected abstract int getPreferencesResource();
protected abstract boolean getSwitchPreferenceDefault();
@Nullable
protected abstract String getSwitchPreferenceKey();
private void updatePreferenceScreen() {
final PreferenceScreen screen = getPreferenceScreen();
final SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences();
if (screen == null || sharedPreferences == null) return;
screen.setEnabled(sharedPreferences.getBoolean(getSwitchPreferenceKey(), getSwitchPreferenceDefault()));
}
}

View File

@ -1,121 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.preference.RingtonePreference;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.UserColorNameManager;
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import javax.inject.Inject;
public abstract class BasePreferenceFragment extends PreferenceFragmentCompat implements Constants {
private static final int REQUEST_PICK_RINGTONE = 301;
private static final String EXTRA_RINGTONE_PREFERENCE_KEY = "internal:ringtone_preference_key";
private String mRingtonePreferenceKey;
@Inject
protected KeyboardShortcutsHandler mKeyboardShortcutHandler;
@Inject
protected UserColorNameManager mUserColorNameManager;
@Override
public void onAttach(Context context) {
super.onAttach(context);
GeneralComponentHelper.build(context).inject(this);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
if (savedInstanceState != null) {
mRingtonePreferenceKey = savedInstanceState.getString(EXTRA_RINGTONE_PREFERENCE_KEY);
}
super.onActivityCreated(savedInstanceState);
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(EXTRA_RINGTONE_PREFERENCE_KEY, mRingtonePreferenceKey);
super.onSaveInstanceState(outState);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_PICK_RINGTONE: {
if (resultCode == Activity.RESULT_OK && data != null) {
Uri ringtone = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (mRingtonePreferenceKey != null) {
RingtonePreference ringtonePreference = (RingtonePreference)
findPreference(mRingtonePreferenceKey);
if (ringtonePreference != null) {
ringtonePreference.setValue(ringtone != null ? ringtone.toString() : null);
}
}
mRingtonePreferenceKey = null;
}
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (preference instanceof RingtonePreference) {
RingtonePreference ringtonePreference = (RingtonePreference) preference;
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, ringtonePreference.getRingtoneType());
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, ringtonePreference.isShowDefault());
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, ringtonePreference.isShowSilent());
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI);
String existingValue = ringtonePreference.getValue(); // TODO
if (existingValue != null) {
if (existingValue.length() == 0) {
// Select "Silent"
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
} else {
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(existingValue));
}
} else {
// No ringtone has been selected, set to the default
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Settings.System.DEFAULT_NOTIFICATION_URI);
}
startActivityForResult(intent, REQUEST_PICK_RINGTONE);
mRingtonePreferenceKey = ringtonePreference.getKey();
return true;
}
return super.onPreferenceTreeClick(preference);
}
}

View File

@ -1,116 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import org.mariotaku.twidere.util.support.WebSettingsSupport;
import org.mariotaku.twidere.util.webkit.DefaultWebViewClient;
@SuppressLint("SetJavaScriptEnabled")
public class BaseSupportWebViewFragment extends BaseSupportFragment {
private WebView mWebView;
private boolean mIsWebViewAvailable;
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final WebView view = getWebView();
view.setWebViewClient(createWebViewClient());
final WebSettings settings = view.getSettings();
settings.setBuiltInZoomControls(true);
settings.setJavaScriptEnabled(true);
WebSettingsSupport.setAllowUniversalAccessFromFileURLs(settings, true);
}
protected WebViewClient createWebViewClient() {
return new DefaultWebViewClient(getActivity());
}
/**
* Called to instantiate the view. Creates and returns the WebView.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (mWebView != null) {
mWebView.destroy();
}
mWebView = new WebView(getActivity());
mIsWebViewAvailable = true;
return mWebView;
}
/**
* Called when the fragment is visible to the user and actively running. Resumes the WebView.
*/
@Override
public void onPause() {
super.onPause();
mWebView.onPause();
}
/**
* Called when the fragment is no longer resumed. Pauses the WebView.
*/
@Override
public void onResume() {
mWebView.onResume();
super.onResume();
}
/**
* Called when the WebView has been detached from the fragment.
* The WebView is no longer available after this time.
*/
@Override
public void onDestroyView() {
mIsWebViewAvailable = false;
super.onDestroyView();
}
/**
* Called when the fragment is no longer in use. Destroys the internal state of the WebView.
*/
@Override
public void onDestroy() {
if (mWebView != null) {
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
/**
* Gets the WebView.
*/
public WebView getWebView() {
return mIsWebViewAvailable ? mWebView : null;
}
}

View File

@ -79,6 +79,17 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import static org.mariotaku.twidere.Constants.EXTRA_ARGUMENTS;
import static org.mariotaku.twidere.Constants.EXTRA_EXTRAS;
import static org.mariotaku.twidere.Constants.EXTRA_ICON;
import static org.mariotaku.twidere.Constants.EXTRA_ID;
import static org.mariotaku.twidere.Constants.EXTRA_NAME;
import static org.mariotaku.twidere.Constants.EXTRA_TYPE;
import static org.mariotaku.twidere.Constants.INTENT_ACTION_ADD_TAB;
import static org.mariotaku.twidere.Constants.INTENT_ACTION_EDIT_TAB;
import static org.mariotaku.twidere.Constants.REQUEST_ADD_TAB;
import static org.mariotaku.twidere.Constants.REQUEST_EDIT_TAB;
public class CustomTabsFragment extends BaseSupportFragment implements LoaderCallbacks<Cursor>,
MultiChoiceModeListener, OnItemClickListener {

View File

@ -43,7 +43,7 @@ public class DestroySavedSearchDialogFragment extends BaseDialogFragment impleme
final UserKey accountKey = getAccountKey();
final long searchId = getSearchId();
final AsyncTwitterWrapper twitter = twitterWrapper;
if (searchId <= 0 || twitter == null) return;
if (searchId <= 0) return;
twitter.destroySavedSearchAsync(accountKey, searchId);
break;
default:

View File

@ -41,7 +41,7 @@ public class DestroyStatusDialogFragment extends BaseDialogFragment implements D
case DialogInterface.BUTTON_POSITIVE:
final ParcelableStatus status = getStatus();
final AsyncTwitterWrapper twitter = twitterWrapper;
if (status == null || twitter == null) return;
if (status == null) return;
twitter.destroyStatusAsync(status.account_key, status.id);
break;
default:

View File

@ -1,164 +0,0 @@
package org.mariotaku.twidere.fragment;
import android.content.Context;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import org.mariotaku.microblog.library.MicroBlog;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.statusnet.model.Group;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.SupportTabsAdapter;
import org.mariotaku.twidere.model.ParcelableGroup;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableGroupUtils;
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
import org.mariotaku.twidere.util.Utils;
/**
* Created by mariotaku on 16/3/23.
*/
public class GroupFragment extends AbsToolbarTabPagesFragment implements
LoaderCallbacks<SingleResponse<ParcelableGroup>> {
private ParcelableGroup mGroup;
private boolean mGroupLoaderInitialized;
@Override
protected void addTabs(SupportTabsAdapter adapter) {
final Bundle args = getArguments();
adapter.addTab(GroupTimelineFragment.class, args, getString(R.string.statuses), 0, 0, "statuses");
adapter.addTab(GroupMembersFragment.class, args, getString(R.string.members), 0, 1, "members");
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Utils.setNdefPushMessageCallback(getActivity(), new NfcAdapter.CreateNdefMessageCallback() {
@Override
public NdefMessage createNdefMessage(NfcEvent event) {
final ParcelableGroup group = getGroup();
if (group == null || group.url == null) return null;
return new NdefMessage(new NdefRecord[]{
NdefRecord.createUri(group.url),
});
}
});
getGroupInfo(false);
}
@Override
public Loader<SingleResponse<ParcelableGroup>> onCreateLoader(int id, Bundle args) {
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final String groupId = args.getString(EXTRA_GROUP_ID);
final String groupName = args.getString(EXTRA_GROUP_NAME);
final boolean omitIntentExtra = args.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true);
return new ParcelableGroupLoader(getContext(), omitIntentExtra, getArguments(), accountKey,
groupId, groupName);
}
@Override
public void onLoadFinished(Loader<SingleResponse<ParcelableGroup>> loader, SingleResponse<ParcelableGroup> data) {
if (data.hasData()) {
displayGroup(data.getData());
}
}
@Override
public void onLoaderReset(Loader<SingleResponse<ParcelableGroup>> loader) {
}
public void displayGroup(final ParcelableGroup group) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
getLoaderManager().destroyLoader(0);
mGroup = group;
if (group != null) {
activity.setTitle(group.fullname);
} else {
activity.setTitle(R.string.user_list);
}
invalidateOptionsMenu();
}
public void getGroupInfo(final boolean omitIntentExtra) {
final LoaderManager lm = getLoaderManager();
lm.destroyLoader(0);
final Bundle args = new Bundle(getArguments());
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra);
if (!mGroupLoaderInitialized) {
lm.initLoader(0, args, this);
mGroupLoaderInitialized = true;
} else {
lm.restartLoader(0, args, this);
}
}
public ParcelableGroup getGroup() {
return mGroup;
}
static class ParcelableGroupLoader extends AsyncTaskLoader<SingleResponse<ParcelableGroup>> {
private final boolean mOmitIntentExtra;
private final Bundle mExtras;
private final UserKey mAccountKey;
private final String mGroupId;
private final String mGroupName;
private ParcelableGroupLoader(final Context context, final boolean omitIntentExtra,
final Bundle extras, final UserKey accountKey,
final String groupId, final String groupName) {
super(context);
mOmitIntentExtra = omitIntentExtra;
mExtras = extras;
mAccountKey = accountKey;
mGroupId = groupId;
mGroupName = groupName;
}
@Override
public SingleResponse<ParcelableGroup> loadInBackground() {
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableGroup cache = mExtras.getParcelable(EXTRA_GROUP);
if (cache != null) return SingleResponse.Companion.getInstance(cache);
}
final MicroBlog twitter = MicroBlogAPIFactory.getInstance(getContext(), mAccountKey,
true);
if (twitter == null) return SingleResponse.Companion.getInstance();
try {
final Group group;
if (mGroupId != null) {
group = twitter.showGroup(mGroupId);
} else if (mGroupName != null) {
group = twitter.showGroupByName(mGroupName);
} else {
return SingleResponse.Companion.getInstance();
}
return SingleResponse.Companion.getInstance(ParcelableGroupUtils.from(group, mAccountKey, 0,
group.isMember()));
} catch (final MicroBlogException e) {
return SingleResponse.Companion.getInstance(e);
}
}
@Override
public void onStartLoading() {
forceLoad();
}
}
}

View File

@ -1,17 +0,0 @@
package org.mariotaku.twidere.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.mariotaku.twidere.R;
public class InvalidTabFragment extends BaseSupportFragment {
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_invalid_tab, container, false);
}
}

View File

@ -91,7 +91,7 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
setTitle(KeyboardShortcutsHandler.getActionLabel(context, action));
mPreferencesChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
updateSummary();
}
};

View File

@ -52,6 +52,10 @@ import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Locale;
import static org.mariotaku.twidere.Constants.DEFAULT_TWITTER_API_URL_FORMAT;
import static org.mariotaku.twidere.Constants.KEY_BUILTIN_DNS_RESOLVER;
import static org.mariotaku.twidere.Constants.KEY_DNS_SERVER;
import static org.mariotaku.twidere.Constants.KEY_TCP_DNS_QUERY;
/**
* Network diagnostics

View File

@ -1,129 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.ComposeActivity;
import org.mariotaku.twidere.activity.LinkHandlerActivity;
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarOffsetListener;
import org.mariotaku.twidere.adapter.SupportTabsAdapter;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.provider.RecentSearchProvider;
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class SearchFragment extends AbsToolbarTabPagesFragment implements RefreshScrollTopInterface,
SupportFragmentCallback, SystemWindowsInsetsCallback, ControlBarOffsetListener,
OnPageChangeListener, LinkHandlerActivity.HideUiOnScroll {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
final String query = getQuery();
if (savedInstanceState == null && !TextUtils.isEmpty(query)) {
final SearchRecentSuggestions suggestions = new SearchRecentSuggestions(getActivity(),
RecentSearchProvider.AUTHORITY, RecentSearchProvider.MODE);
suggestions.saveRecentQuery(query, null);
final ContentResolver cr = getContentResolver();
final ContentValues values = new ContentValues();
values.put(SearchHistory.QUERY, query);
cr.insert(SearchHistory.CONTENT_URI, values);
}
}
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.menu_search, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
if (isDetached() || getActivity() == null) return;
final MenuItem item = menu.findItem(R.id.compose);
item.setTitle(getString(R.string.tweet_hashtag, getQuery()));
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final String query = getQuery();
switch (item.getItemId()) {
case R.id.save: {
final AsyncTwitterWrapper twitter = twitterWrapper;
final Bundle args = getArguments();
if (twitter != null && args != null) {
twitter.createSavedSearchAsync(getAccountKey(), query);
}
return true;
}
case R.id.compose: {
final Intent intent = new Intent(getActivity(), ComposeActivity.class);
intent.setAction(INTENT_ACTION_COMPOSE);
if (query.startsWith("@") || query.startsWith("\uff20")) {
intent.putExtra(Intent.EXTRA_TEXT, query);
} else {
intent.putExtra(Intent.EXTRA_TEXT, String.format("#%s ", query));
}
intent.putExtra(EXTRA_ACCOUNT_KEY, getAccountKey());
startActivity(intent);
break;
}
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean triggerRefresh(final int position) {
return false;
}
public UserKey getAccountKey() {
return getArguments().getParcelable(EXTRA_ACCOUNT_KEY);
}
public String getQuery() {
return getArguments().getString(EXTRA_QUERY);
}
@Override
protected void addTabs(SupportTabsAdapter adapter) {
final Bundle args = getArguments();
adapter.addTab(StatusesSearchFragment.class, args, getString(R.string.statuses), R.drawable.ic_action_twitter, 0, null);
adapter.addTab(SearchUsersFragment.class, args, getString(R.string.users), R.drawable.ic_action_user, 1, null);
}
}

View File

@ -1,98 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
import org.mariotaku.twidere.activity.SettingsActivity;
import org.mariotaku.twidere.util.Utils;
public class SettingsDetailsFragment extends BasePreferenceFragment implements
OnSharedPreferenceChangeListener {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
final PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setSharedPreferencesName(SHARED_PREFERENCES_NAME);
final PreferenceScreen defaultScreen = getPreferenceScreen();
final PreferenceScreen preferenceScreen;
if (defaultScreen != null) {
defaultScreen.removeAll();
preferenceScreen = defaultScreen;
} else {
preferenceScreen = preferenceManager.createPreferenceScreen(getActivity());
}
setPreferenceScreen(preferenceScreen);
final Bundle args = getArguments();
final Object rawResId = args.get(EXTRA_RESID);
final int resId;
if (rawResId instanceof Integer) {
resId = (Integer) rawResId;
} else if (rawResId instanceof String) {
resId = Utils.getResId(getActivity(), (String) rawResId);
} else {
resId = 0;
}
if (resId != 0) {
addPreferencesFromResource(resId);
}
}
@Override
public void onStart() {
super.onStart();
final SharedPreferences preferences = getPreferenceManager().getSharedPreferences();
preferences.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onStop() {
final SharedPreferences preferences = getPreferenceManager().getSharedPreferences();
preferences.unregisterOnSharedPreferenceChangeListener(this);
super.onStop();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
final Preference preference = findPreference(key);
if (preference == null) return;
final Bundle extras = preference.getExtras();
if (extras != null) {
final Activity activity = getActivity();
if (extras.containsKey(EXTRA_NOTIFY_CHANGE)) {
SettingsActivity.setShouldNotifyChange(activity);
}
if (extras.containsKey(EXTRA_RESTART_ACTIVITY)) {
activity.recreate();
}
}
}
}

View File

@ -1,57 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.mariotaku.twidere.R;
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_TAB_POSITION;
/**
* Created by mariotaku on 15/7/4.
*/
public class StubFragment extends Fragment {
private TextView mTextView;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mTextView.setText(String.valueOf(getArguments().get(EXTRA_TAB_POSITION)));
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTextView = (TextView) view.findViewById(R.id.text);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_stub, container, false);
}
}

View File

@ -1,52 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.card;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.webkit.WebSettings;
import android.webkit.WebView;
import org.mariotaku.twidere.fragment.SupportBrowserFragment;
/**
* Created by mariotaku on 15/1/6.
*/
public class CardBrowserFragment extends SupportBrowserFragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final WebView view = getWebView();
final WebSettings settings = view.getSettings();
settings.setBuiltInZoomControls(false);
}
public static CardBrowserFragment show(@NonNull String uri, @Nullable Bundle extraArgs) {
final Bundle args = new Bundle();
args.putString(EXTRA_URI, uri);
if (extraArgs != null) {
args.putAll(extraArgs);
}
final CardBrowserFragment fragment = new CardBrowserFragment();
fragment.setArguments(args);
return fragment;
}
}

View File

@ -1,373 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.card;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;
import android.widget.TableLayout;
import android.widget.TextView;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.abstask.library.TaskStarter;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.twitter.TwitterCaps;
import org.mariotaku.microblog.library.twitter.model.CardDataMap;
import org.mariotaku.microblog.library.twitter.model.CardEntity;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.BaseSupportFragment;
import org.mariotaku.twidere.model.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils;
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
import org.mariotaku.twidere.util.support.ViewSupport;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by mariotaku on 15/12/20.
*/
public class CardPollFragment extends BaseSupportFragment implements
LoaderManager.LoaderCallbacks<ParcelableCardEntity>, View.OnClickListener {
public static final Pattern PATTERN_POLL_TEXT_ONLY = Pattern.compile("poll([\\d]+)choice_text_only");
private TableLayout mPollContainer;
private TextView mPollSummary;
private ParcelableCardEntity mCard;
public static CardPollFragment show(ParcelableStatus status) {
final CardPollFragment fragment = new CardPollFragment();
final Bundle args = new Bundle();
args.putParcelable(EXTRA_STATUS, status);
args.putParcelable(EXTRA_CARD, status.card);
fragment.setArguments(args);
return fragment;
}
public static boolean isPoll(@NonNull ParcelableCardEntity card) {
return PATTERN_POLL_TEXT_ONLY.matcher(card.name).matches() && !TextUtils.isEmpty(card.url);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initChoiceView(savedInstanceState);
getLoaderManager().initLoader(0, null, this);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPollContainer = (TableLayout) view.findViewById(R.id.poll_container);
mPollSummary = (TextView) view.findViewById(R.id.poll_summary);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_card_poll, container, false);
}
@Override
protected void fitSystemWindows(Rect insets) {
// No-op
}
private void initChoiceView(@Nullable Bundle savedInstanceState) {
final ParcelableCardEntity card = getCard();
final ParcelableStatus status = getStatus();
final int choicesCount = getChoicesCount(card);
final LayoutInflater inflater = getLayoutInflater(savedInstanceState);
for (int i = 0; i < choicesCount; i++) {
inflater.inflate(R.layout.layout_poll_item, mPollContainer, true);
}
displayPoll(card, status);
}
private void displayPoll(final ParcelableCardEntity card, final ParcelableStatus status) {
final Context context = getContext();
if (card == null || status == null || context == null) return;
mCard = card;
final int choicesCount = getChoicesCount(card);
int votesSum = 0;
final boolean countsAreFinal = ParcelableCardEntityUtils.getAsBoolean(card, "counts_are_final", false);
final int selectedChoice = ParcelableCardEntityUtils.getAsInteger(card, "selected_choice", -1);
final Date endDatetimeUtc = ParcelableCardEntityUtils.getAsDate(card, "end_datetime_utc", new Date());
final boolean hasChoice = selectedChoice != -1;
final boolean isMyPoll = status.account_key.equals(status.user_key);
final boolean showResult = countsAreFinal || isMyPoll || hasChoice;
for (int i = 0; i < choicesCount; i++) {
final int choiceIndex = i + 1;
votesSum += ParcelableCardEntityUtils.getAsInteger(card, "choice" + choiceIndex + "_count", 0);
}
final View.OnClickListener clickListener = new View.OnClickListener() {
private boolean clickedChoice;
@Override
public void onClick(View v) {
if (hasChoice || clickedChoice) return;
for (int i = 0, j = mPollContainer.getChildCount(); i < j; i++) {
final View pollItem = mPollContainer.getChildAt(i);
pollItem.setClickable(false);
clickedChoice = true;
final RadioButton choiceRadioButton = (RadioButton) pollItem.findViewById(R.id.choice_button);
final boolean checked = v == pollItem;
choiceRadioButton.setChecked(checked);
if (checked) {
final CardDataMap cardData = new CardDataMap();
cardData.putLong("original_tweet_id", NumberUtils.toLong(status.id));
cardData.putString("card_uri", card.url);
cardData.putString("cards_platform", MicroBlogAPIFactory.CARDS_PLATFORM_ANDROID_12);
cardData.putString("response_card_name", card.name);
cardData.putString("selected_choice", String.valueOf(i + 1));
AbstractTask<CardDataMap, ParcelableCardEntity, CardPollFragment> task
= new AbstractTask<CardDataMap, ParcelableCardEntity, CardPollFragment>() {
@Override
public void afterExecute(CardPollFragment handler, ParcelableCardEntity result) {
handler.displayAndReloadPoll(result, status);
}
@Override
public ParcelableCardEntity doLongOperation(CardDataMap cardDataMap) {
final Context context = getContext();
if (context == null) return null;
final TwitterCaps caps = MicroBlogAPIFactory.getInstance(context,
card.account_key, true, true, TwitterCaps.class);
if (caps == null) return null;
try {
final CardEntity cardEntity = caps.sendPassThrough(cardDataMap).getCard();
return ParcelableCardEntityUtils.fromCardEntity(cardEntity,
card.account_key);
} catch (MicroBlogException e) {
Log.w(LOGTAG, e);
}
return null;
}
};
task.setCallback(CardPollFragment.this);
task.setParams(cardData);
TaskStarter.execute(task);
}
}
}
};
final int color = ContextCompat.getColor(context, R.color.material_light_blue_a200);
final float radius = getResources().getDimension(R.dimen.element_spacing_small);
for (int i = 0; i < choicesCount; i++) {
final View pollItem = mPollContainer.getChildAt(i);
final TextView choicePercentView = (TextView) pollItem.findViewById(R.id.choice_percent);
final TextView choiceLabelView = (TextView) pollItem.findViewById(R.id.choice_label);
final RadioButton choiceRadioButton = (RadioButton) pollItem.findViewById(R.id.choice_button);
final int choiceIndex = i + 1;
final String label = ParcelableCardEntityUtils.getAsString(card, "choice" + choiceIndex + "_label", null);
final int value = ParcelableCardEntityUtils.getAsInteger(card, "choice" + choiceIndex + "_count", 0);
if (label == null) throw new NullPointerException();
final float choicePercent = votesSum == 0 ? 0 : value / (float) votesSum;
choiceLabelView.setText(label);
choicePercentView.setText(String.format(Locale.US, "%d%%", Math.round(choicePercent * 100)));
pollItem.setOnClickListener(clickListener);
final boolean isSelected = selectedChoice == choiceIndex;
if (showResult) {
choicePercentView.setVisibility(View.VISIBLE);
choiceRadioButton.setVisibility(hasChoice && isSelected ? View.VISIBLE : View.INVISIBLE);
ViewSupport.setBackground(choiceLabelView, new PercentDrawable(choicePercent, radius, color));
} else {
choicePercentView.setVisibility(View.GONE);
choiceRadioButton.setVisibility(View.VISIBLE);
ViewSupport.setBackground(choiceLabelView, null);
}
choiceRadioButton.setChecked(isSelected);
pollItem.setClickable(selectedChoice == -1);
}
final String nVotes = getResources().getQuantityString(R.plurals.N_votes, votesSum, votesSum);
final CharSequence timeLeft = DateUtils.getRelativeTimeSpanString(context,
endDatetimeUtc.getTime(), true);
mPollSummary.setText(getString(R.string.poll_summary_format, nVotes, timeLeft));
}
private void displayAndReloadPoll(ParcelableCardEntity result, ParcelableStatus status) {
if (getHost() == null) return;
displayPoll(result, status);
getLoaderManager().restartLoader(0, null, this);
}
private int getChoicesCount(ParcelableCardEntity card) {
final Matcher matcher = PATTERN_POLL_TEXT_ONLY.matcher(card.name);
if (!matcher.matches()) throw new IllegalStateException();
return NumberUtils.toInt(matcher.group(1));
}
@NonNull
private ParcelableCardEntity getCard() {
if (mCard != null) return mCard;
final ParcelableCardEntity card = getArguments().getParcelable(EXTRA_CARD);
assert card != null && card.name != null;
return card;
}
private ParcelableStatus getStatus() {
return getArguments().getParcelable(EXTRA_STATUS);
}
@Override
public void onClick(View v) {
}
@Override
public Loader<ParcelableCardEntity> onCreateLoader(int id, Bundle args) {
final ParcelableCardEntity card = getCard();
return new ParcelableCardEntityLoader(getContext(), card.account_key, card.url, card.name);
}
@Override
public void onLoadFinished(Loader<ParcelableCardEntity> loader, ParcelableCardEntity data) {
if (data == null) return;
displayPoll(data, getStatus());
}
@Override
public void onLoaderReset(Loader<ParcelableCardEntity> loader) {
}
private static class PercentDrawable extends Drawable {
private final Paint mPaint;
private final RectF mBounds;
private final float mPercent;
private final float mRadius;
PercentDrawable(float percent, float radius, int color) {
mPercent = percent;
mRadius = radius;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(color);
mBounds = new RectF();
}
@Override
public void draw(Canvas canvas) {
canvas.drawRoundRect(mBounds, mRadius, mRadius, mPaint);
}
@Override
protected void onBoundsChange(Rect bounds) {
mBounds.set(bounds);
mBounds.right = mBounds.left + mBounds.width() * mPercent;
super.onBoundsChange(bounds);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
public static class ParcelableCardEntityLoader extends AsyncTaskLoader<ParcelableCardEntity> {
private final UserKey mAccountKey;
private final String mCardUri;
private final String mCardName;
public ParcelableCardEntityLoader(Context context, UserKey accountKey,
String cardUri, String cardName) {
super(context);
mAccountKey = accountKey;
mCardUri = cardUri;
mCardName = cardName;
}
@Override
public ParcelableCardEntity loadInBackground() {
final TwitterCaps caps = MicroBlogAPIFactory.getInstance(getContext(), mAccountKey,
true, true, TwitterCaps.class);
if (caps == null) return null;
try {
final CardDataMap params = new CardDataMap();
params.putString("card_uri", mCardUri);
params.putString("cards_platform", MicroBlogAPIFactory.CARDS_PLATFORM_ANDROID_12);
params.putString("response_card_name", mCardName);
final CardEntity card = caps.getPassThrough(params).getCard();
if (card == null || card.getName() == null) {
return null;
}
return ParcelableCardEntityUtils.fromCardEntity(card, mAccountKey);
} catch (MicroBlogException e) {
return null;
}
}
@Override
protected void onStartLoading() {
forceLoad();
}
}
}

View File

@ -1,79 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface;
import android.graphics.Rect;
import android.os.Bundle;
import java.util.LinkedList;
import java.util.Queue;
public interface IBaseFragment {
Bundle getExtraConfiguration();
int getTabPosition();
void requestFitSystemWindows();
interface SystemWindowsInsetsCallback {
boolean getSystemWindowsInsets(Rect insets);
}
void executeAfterFragmentResumed(Action action);
interface Action {
void execute(IBaseFragment fragment);
}
class ActionHelper {
private final IBaseFragment mFragment;
private boolean mFragmentResumed;
private Queue<Action> mActionQueue = new LinkedList<>();
public ActionHelper(IBaseFragment fragment) {
mFragment = fragment;
}
public void dispatchOnPause() {
mFragmentResumed = false;
}
public void dispatchOnResumeFragments() {
mFragmentResumed = true;
executePending();
}
private void executePending() {
if (!mFragmentResumed) return;
Action action;
while ((action = mActionQueue.poll()) != null) {
action.execute(mFragment);
}
}
public void executeAfterFragmentResumed(Action action) {
mActionQueue.add(action);
executePending();
}
}
}

View File

@ -0,0 +1,68 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface
import android.graphics.Rect
import android.os.Bundle
import java.util.*
interface IBaseFragment {
val extraConfiguration: Bundle?
val tabPosition: Int
fun requestFitSystemWindows()
interface SystemWindowsInsetsCallback {
fun getSystemWindowsInsets(insets: Rect): Boolean
}
fun executeAfterFragmentResumed(action: (IBaseFragment) -> Unit)
class ActionHelper(private val fragment: IBaseFragment) {
private var fragmentResumed: Boolean = false
private val actionQueue = LinkedList<(IBaseFragment) -> Unit>()
fun dispatchOnPause() {
fragmentResumed = false
}
fun dispatchOnResumeFragments() {
fragmentResumed = true
executePending()
}
private fun executePending() {
if (!fragmentResumed) return
var action: ((IBaseFragment) -> Unit)?
do {
action = actionQueue.poll()
action?.invoke(fragment)
} while (action != null)
}
fun executeAfterFragmentResumed(action: (IBaseFragment) -> Unit) {
actionQueue.add(action)
executePending()
}
}
}

View File

@ -17,12 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface;
package org.mariotaku.twidere.fragment.iface
public interface IDialogFragmentCallback {
interface IDialogFragmentCallback {
void onCancelled();
fun onCancelled()
void onDismissed();
fun onDismissed()
}

View File

@ -17,10 +17,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface;
package org.mariotaku.twidere.fragment.iface
public interface IMapFragment {
interface IMapFragment {
void center();
fun center()
}

View File

@ -1,30 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface;
import android.support.v4.app.DialogFragment;
public interface ISupportDialogFragmentCallback {
void onCancelled(DialogFragment df);
void onDismissed(DialogFragment df);
}

View File

@ -17,13 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface;
package org.mariotaku.twidere.fragment.iface
public interface IBasePullToRefreshFragment {
import android.support.v4.app.DialogFragment
void onRefresh();
interface ISupportDialogFragmentCallback {
boolean isRefreshing();
fun onCancelled(df: DialogFragment)
fun onDismissed(df: DialogFragment)
void setRefreshing(boolean refresh);
}

View File

@ -17,12 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface;
package org.mariotaku.twidere.fragment.iface
public interface RefreshScrollTopInterface {
interface RefreshScrollTopInterface {
boolean scrollToStart();
fun scrollToStart(): Boolean
boolean triggerRefresh();
fun triggerRefresh(): Boolean
}

View File

@ -17,14 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.iface;
package org.mariotaku.twidere.fragment.iface
import android.support.v4.app.Fragment;
import android.support.v4.app.Fragment
public interface SupportFragmentCallback {
interface SupportFragmentCallback {
Fragment getCurrentVisibleFragment();
val currentVisibleFragment: Fragment?
boolean triggerRefresh(int position);
fun triggerRefresh(position: Int): Boolean
}

View File

@ -143,7 +143,7 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
notifyChanged();
}

View File

@ -72,7 +72,7 @@ public class KeyboardShortcutPreference extends DialogPreference implements IDia
setTitle(KeyboardShortcutsHandler.getActionLabel(context, mAction));
mPreferencesChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
updateSummary();
}
};

View File

@ -610,7 +610,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
updatePreferences();
}

View File

@ -17,18 +17,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
package org.mariotaku.twidere.util
import android.content.Context;
import android.support.v4.app.Fragment;
import android.content.Context
import android.support.v4.app.Fragment
/**
* Created by mariotaku on 15/4/27.
*/
public abstract class MapFragmentFactory {
abstract class MapFragmentFactory {
public static final MapFragmentFactory SINGLETON = new MapFragmentFactoryImpl();
abstract fun createMapFragment(context: Context): Fragment?
public abstract Fragment createMapFragment(Context context);
companion object {
fun getInstance(): MapFragmentFactory = MapFragmentFactoryImpl()
}
}

View File

@ -1,58 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import org.mariotaku.twidere.fragment.card.CardBrowserFragment;
import org.mariotaku.twidere.fragment.card.CardPollFragment;
import org.mariotaku.twidere.model.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils;
/**
* Created by mariotaku on 15/1/1.
*/
public abstract class TwitterCardFragmentFactory {
public abstract Fragment createAnimatedGifFragment(ParcelableCardEntity card);
public abstract Fragment createAudioFragment(ParcelableCardEntity card);
public abstract Fragment createPlayerFragment(ParcelableCardEntity card);
public static TwitterCardFragmentFactory getInstance() {
return new TwitterCardFragmentFactoryImpl();
}
@Nullable
public static Fragment createGenericPlayerFragment(@Nullable ParcelableCardEntity card, Bundle args) {
if (card == null) return null;
final String playerUrl = ParcelableCardEntityUtils.getString(card, "player_url");
if (playerUrl == null) return null;
return CardBrowserFragment.show(playerUrl, args);
}
public static Fragment createCardPollFragment(ParcelableStatus status) {
return CardPollFragment.show(status);
}
}

View File

@ -0,0 +1,57 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util
import android.os.Bundle
import android.support.v4.app.Fragment
import org.mariotaku.twidere.fragment.card.CardBrowserFragment
import org.mariotaku.twidere.fragment.card.CardPollFragment
import org.mariotaku.twidere.model.ParcelableCardEntity
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils
/**
* Created by mariotaku on 15/1/1.
*/
abstract class TwitterCardFragmentFactory {
abstract fun createAnimatedGifFragment(card: ParcelableCardEntity): Fragment?
abstract fun createAudioFragment(card: ParcelableCardEntity): Fragment?
abstract fun createPlayerFragment(card: ParcelableCardEntity): Fragment?
companion object {
val instance: TwitterCardFragmentFactory
get() = TwitterCardFragmentFactoryImpl()
fun createGenericPlayerFragment(card: ParcelableCardEntity?, args: Bundle?): Fragment? {
if (card == null) return null
val playerUrl = ParcelableCardEntityUtils.getString(card, "player_url") ?: return null
return CardBrowserFragment.show(playerUrl, args)
}
fun createCardPollFragment(status: ParcelableStatus): Fragment {
return CardPollFragment.show(status)
}
}
}

View File

@ -1,109 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.fragment.card.CardPollFragment;
import org.mariotaku.twidere.model.ParcelableCardEntity;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils;
/**
* Created by mariotaku on 15/1/1.
*/
public class TwitterCardUtils {
private static final TwitterCardFragmentFactory sFactory = TwitterCardFragmentFactory.getInstance();
public static final String CARD_NAME_PLAYER = "player";
public static final String CARD_NAME_AUDIO = "audio";
public static final String CARD_NAME_ANIMATED_GIF = "animated_gif";
private TwitterCardUtils() {
}
@Nullable
public static Fragment createCardFragment(ParcelableStatus status) {
final ParcelableCardEntity card = status.card;
if (card == null || card.name == null) return null;
if (CARD_NAME_PLAYER.equals(card.name)) {
final Fragment playerFragment = sFactory.createPlayerFragment(card);
if (playerFragment != null) return playerFragment;
return TwitterCardFragmentFactory.createGenericPlayerFragment(card, null);
} else if (CARD_NAME_AUDIO.equals(card.name)) {
final Fragment playerFragment = sFactory.createAudioFragment(card);
if (playerFragment != null) return playerFragment;
return TwitterCardFragmentFactory.createGenericPlayerFragment(card, null);
} else if (CARD_NAME_ANIMATED_GIF.equals(card.name)) {
final Fragment playerFragment = sFactory.createAnimatedGifFragment(card);
if (playerFragment != null) return playerFragment;
return TwitterCardFragmentFactory.createGenericPlayerFragment(card, null);
} else if (CardPollFragment.isPoll(card)) {
return TwitterCardFragmentFactory.createCardPollFragment(status);
}
return null;
}
public static Point getCardSize(ParcelableCardEntity card) {
final int playerWidth = ParcelableCardEntityUtils.getAsInteger(card, "player_width", -1);
final int playerHeight = ParcelableCardEntityUtils.getAsInteger(card, "player_height", -1);
if (playerWidth > 0 && playerHeight > 0) {
return new Point(playerWidth, playerHeight);
}
return null;
}
public static boolean isCardSupported(ParcelableStatus status) {
if (status.card == null || status.card_name == null) return false;
switch (status.card_name) {
case CARD_NAME_PLAYER: {
if (!ArrayUtils.isEmpty(status.media)) {
String appUrlResolved = ParcelableCardEntityUtils.getString(status.card, "app_url_resolved");
String cardUrl = status.card.url;
for (ParcelableMedia media : status.media) {
if (media.url.equals(appUrlResolved) || media.url.equals(cardUrl)) {
return false;
}
}
}
return TextUtils.isEmpty(ParcelableCardEntityUtils.getString(status.card, "player_stream_url"));
}
case CARD_NAME_AUDIO: {
return true;
}
}
if (CardPollFragment.isPoll(status.card)) {
return true;
}
return false;
}
public static boolean isPoll(ParcelableStatus status) {
if (status.card_name == null || status.card == null) return false;
return CardPollFragment.isPoll(status.card);
}
}

View File

@ -0,0 +1,102 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util
import android.graphics.Point
import android.support.v4.app.Fragment
import android.text.TextUtils
import org.apache.commons.lang3.ArrayUtils
import org.mariotaku.twidere.fragment.card.CardPollFragment
import org.mariotaku.twidere.model.ParcelableCardEntity
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils
/**
* Created by mariotaku on 15/1/1.
*/
object TwitterCardUtils {
private val sFactory = TwitterCardFragmentFactory.instance
val CARD_NAME_PLAYER = "player"
val CARD_NAME_AUDIO = "audio"
val CARD_NAME_ANIMATED_GIF = "animated_gif"
fun createCardFragment(status: ParcelableStatus): Fragment? {
val card = status.card
if (card == null || card.name == null) return null
if (CARD_NAME_PLAYER == card.name) {
val playerFragment = sFactory.createPlayerFragment(card)
if (playerFragment != null) return playerFragment
return TwitterCardFragmentFactory.createGenericPlayerFragment(card, null)
} else if (CARD_NAME_AUDIO == card.name) {
val playerFragment = sFactory.createAudioFragment(card)
if (playerFragment != null) return playerFragment
return TwitterCardFragmentFactory.createGenericPlayerFragment(card, null)
} else if (CARD_NAME_ANIMATED_GIF == card.name) {
val playerFragment = sFactory.createAnimatedGifFragment(card)
if (playerFragment != null) return playerFragment
return TwitterCardFragmentFactory.createGenericPlayerFragment(card, null)
} else if (CardPollFragment.isPoll(card)) {
return TwitterCardFragmentFactory.createCardPollFragment(status)
}
return null
}
fun getCardSize(card: ParcelableCardEntity): Point? {
val playerWidth = ParcelableCardEntityUtils.getAsInteger(card, "player_width", -1)
val playerHeight = ParcelableCardEntityUtils.getAsInteger(card, "player_height", -1)
if (playerWidth > 0 && playerHeight > 0) {
return Point(playerWidth, playerHeight)
}
return null
}
fun isCardSupported(status: ParcelableStatus): Boolean {
val card = status.card ?: return false
when (status.card_name) {
CARD_NAME_PLAYER -> {
if (!ArrayUtils.isEmpty(status.media)) {
val appUrlResolved = ParcelableCardEntityUtils.getString(card, "app_url_resolved")
val cardUrl = card.url
for (media in status.media) {
if (media.url == appUrlResolved || media.url == cardUrl) {
return false
}
}
}
return TextUtils.isEmpty(ParcelableCardEntityUtils.getString(card, "player_stream_url"))
}
CARD_NAME_AUDIO -> {
return true
}
}
if (CardPollFragment.isPoll(card)) {
return true
}
return false
}
fun isPoll(status: ParcelableStatus): Boolean {
val card = status.card ?: return false
return CardPollFragment.isPoll(card)
}
}

View File

@ -256,10 +256,10 @@ public class UserColorNameManager implements TwidereConstants {
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
final UserKey userId = UserKey.valueOf(key);
if (mListener != null && userId != null) {
mListener.onUserColorChanged(userId, sharedPreferences.getInt(key, 0));
mListener.onUserColorChanged(userId, preferences.getInt(key, 0));
}
}
@ -274,10 +274,10 @@ public class UserColorNameManager implements TwidereConstants {
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
final UserKey userId = UserKey.valueOf(key);
if (mListener != null && userId != null) {
mListener.onUserNicknameChanged(userId, sharedPreferences.getString(key, null));
mListener.onUserNicknameChanged(userId, preferences.getString(key, null));
}
}

View File

@ -480,7 +480,7 @@ public final class Utils implements Constants {
args.putDouble(EXTRA_LATITUDE, lat);
args.putDouble(EXTRA_LONGITUDE, lng);
}
fragment = MapFragmentFactory.SINGLETON.createMapFragment(context);
fragment = MapFragmentFactory.Companion.getInstance().createMapFragment(context);
break;
}
case LINK_ID_STATUS: {

View File

@ -437,6 +437,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
replyButton.setOnClickListener(eventListener)
retweetButton.setOnClickListener(eventListener)
favoriteButton.setOnClickListener(eventListener)
mediaLabel.setOnClickListener(eventListener)
quotedMediaLabel.setOnClickListener(eventListener)
}

View File

@ -140,11 +140,12 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
return DataStoreUtils.getActivatedAccountKeys(this)
}
override fun getCurrentVisibleFragment(): Fragment? {
val currentItem = mainPager!!.currentItem
if (currentItem < 0 || currentItem >= pagerAdapter!!.count) return null
return pagerAdapter!!.instantiateItem(mainPager, currentItem) as Fragment
}
override val currentVisibleFragment: Fragment?
get() {
val currentItem = mainPager!!.currentItem
if (currentItem < 0 || currentItem >= pagerAdapter!!.count) return null
return pagerAdapter!!.instantiateItem(mainPager, currentItem) as Fragment
}
override fun triggerRefresh(position: Int): Boolean {
val f = pagerAdapter!!.instantiateItem(mainPager, position) as Fragment

View File

@ -61,9 +61,10 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
private var mHideOffsetNotSupported: Boolean = false
override fun getCurrentVisibleFragment(): Fragment {
return supportFragmentManager.findFragmentById(android.R.id.content)
}
override val currentVisibleFragment: Fragment?
get() {
return supportFragmentManager.findFragmentById(android.R.id.content)
}
override fun triggerRefresh(position: Int): Boolean {
return false

View File

@ -27,6 +27,7 @@ import android.os.Bundle
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.CursorLoader
import android.support.v4.content.Loader
import android.support.v4.widget.CursorAdapter
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
@ -58,32 +59,32 @@ import org.mariotaku.twidere.view.iface.IExtendedView.OnFitSystemWindowsListener
/**
* Created by mariotaku on 15/1/6.
*/
class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<Cursor>,
class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<Cursor?>,
OnItemSelectedListener, OnItemClickListener, OnFitSystemWindowsListener,
SwipeDismissListViewTouchListener.DismissCallbacks {
private var usersSearchAdapter: SuggestionsAdapter? = null
private val mSystemWindowsInsets = Rect()
private var textChanged: Boolean = false
override fun canDismiss(position: Int): Boolean {
return usersSearchAdapter!!.getItemViewType(position) == SuggestionsAdapter.VIEW_TYPE_SEARCH_HISTORY
val adapter = suggestionsList.adapter as SuggestionsAdapter
return adapter.getItemViewType(position) == SuggestionsAdapter.VIEW_TYPE_SEARCH_HISTORY
}
override fun onDismiss(listView: ListView, reverseSortedPositions: IntArray) {
val adapter = suggestionsList.adapter as SuggestionsAdapter
val ids = LongArray(reverseSortedPositions.size)
var i = 0
val j = reverseSortedPositions.size
while (i < j) {
val position = reverseSortedPositions[i]
val item = usersSearchAdapter!!.getSuggestionItem(position) ?: return
val item = adapter.getSuggestionItem(position) ?: return
ids[i] = item._id
i++
}
usersSearchAdapter!!.addRemovedPositions(reverseSortedPositions)
val cr = contentResolver
ContentResolverUtils.bulkDelete(cr, SearchHistory.CONTENT_URI, SearchHistory._ID, ids,
null)
adapter.addRemovedPositions(reverseSortedPositions)
ContentResolverUtils.bulkDelete(contentResolver, SearchHistory.CONTENT_URI,
SearchHistory._ID, ids, null)
supportLoaderManager.restartLoader(0, null, this)
}
@ -95,7 +96,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
}
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<Cursor> {
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor?> {
val accountId = selectedAccountKey
val builder = Suggestions.Search.CONTENT_URI.buildUpon()
builder.appendQueryParameter(QUERY_PARAM_QUERY, ParseUtils.parseString(searchQuery.text))
@ -105,12 +106,14 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
return CursorLoader(this, builder.build(), Suggestions.Search.COLUMNS, null, null, null)
}
override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) {
usersSearchAdapter!!.changeCursor(data)
override fun onLoadFinished(loader: Loader<Cursor?>, data: Cursor?) {
val adapter = suggestionsList.adapter as SuggestionsAdapter
adapter.changeCursor(data)
}
override fun onLoaderReset(loader: Loader<Cursor>) {
usersSearchAdapter!!.changeCursor(null)
override fun onLoaderReset(loader: Loader<Cursor?>) {
val adapter = suggestionsList.adapter as SuggestionsAdapter
adapter.changeCursor(null)
}
override fun onFitSystemWindows(insets: Rect) {
@ -119,8 +122,9 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
}
override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
val item = usersSearchAdapter!!.getSuggestionItem(position)
when (usersSearchAdapter!!.getItemViewType(position)) {
val adapter = (suggestionsList.adapter ?: return) as SuggestionsAdapter
val item = adapter.getSuggestionItem(position)
when (adapter.getItemViewType(position)) {
SuggestionsAdapter.VIEW_TYPE_USER_SUGGESTION_ITEM -> {
IntentUtils.openUserProfile(this, selectedAccountKey,
UserKey.valueOf(item!!.extra_id), item.summary, null,
@ -182,8 +186,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
}
}
mainContent.setOnFitSystemWindowsListener(this)
usersSearchAdapter = SuggestionsAdapter(this)
suggestionsList.adapter = usersSearchAdapter
suggestionsList.adapter = SuggestionsAdapter(this)
suggestionsList.onItemClickListener = this
val listener = SwipeDismissListViewTouchListener(suggestionsList, this)
@ -268,20 +271,22 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
}
}
class SuggestionsAdapter internal constructor(private val mActivity: QuickSearchBarActivity) : CursorAdapter(mActivity, null, 0), OnClickListener {
class SuggestionsAdapter internal constructor(
private val activity: QuickSearchBarActivity
) : CursorAdapter(activity, null, 0), OnClickListener {
private val mInflater: LayoutInflater
private val mMediaLoader: MediaLoaderWrapper
private val mUserColorNameManager: UserColorNameManager
private val mRemovedPositions: SortableIntList?
private val removedPositions: SortableIntList?
private var mIndices: Indices? = null
private var indices: Indices? = null
init {
mRemovedPositions = SortableIntList()
mMediaLoader = mActivity.mediaLoader
mUserColorNameManager = mActivity.userColorNameManager
mInflater = LayoutInflater.from(mActivity)
removedPositions = SortableIntList()
mMediaLoader = activity.mediaLoader
mUserColorNameManager = activity.userColorNameManager
mInflater = LayoutInflater.from(activity)
}
override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
@ -304,40 +309,40 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
internal fun getSuggestionItem(position: Int): SuggestionItem? {
val cursor = getItem(position) as Cursor? ?: return null
val indices = mIndices ?: return null
val indices = indices ?: return null
return SuggestionItem(cursor, indices)
}
override fun bindView(view: View, context: Context, cursor: Cursor) {
if (mIndices == null) throw NullPointerException()
val indices = indices!!
when (getActualItemViewType(cursor.position)) {
VIEW_TYPE_SEARCH_HISTORY -> {
val holder = view.tag as SearchViewHolder
val title = cursor.getString(mIndices!!.title)
val title = cursor.getString(indices.title)
holder.edit_query.tag = title
holder.text1.text = title
holder.icon.setImageResource(R.drawable.ic_action_history)
}
VIEW_TYPE_SAVED_SEARCH -> {
val holder = view.tag as SearchViewHolder
val title = cursor.getString(mIndices!!.title)
val title = cursor.getString(indices.title)
holder.edit_query.tag = title
holder.text1.text = title
holder.icon.setImageResource(R.drawable.ic_action_save)
}
VIEW_TYPE_USER_SUGGESTION_ITEM -> {
val holder = view.tag as UserViewHolder
val userKey = UserKey.valueOf(cursor.getString(mIndices!!.extra_id))!!
val userKey = UserKey.valueOf(cursor.getString(indices.extra_id))!!
holder.text1.text = mUserColorNameManager.getUserNickname(userKey,
cursor.getString(mIndices!!.title))
cursor.getString(indices.title))
holder.text2.visibility = View.VISIBLE
holder.text2.text = String.format("@%s", cursor.getString(mIndices!!.summary))
holder.text2.text = "@${cursor.getString(indices.summary)}"
holder.icon.clearColorFilter()
mMediaLoader.displayProfileImage(holder.icon, cursor.getString(mIndices!!.icon))
mMediaLoader.displayProfileImage(holder.icon, cursor.getString(indices.icon))
}
VIEW_TYPE_USER_SCREEN_NAME -> {
val holder = view.tag as UserViewHolder
holder.text1.text = String.format("@%s", cursor.getString(mIndices!!.title))
holder.text1.text = "@${cursor.getString(indices.title)}"
holder.text2.visibility = View.GONE
holder.icon.setColorFilter(holder.text1.currentTextColor, Mode.SRC_ATOP)
mMediaLoader.cancelDisplayTask(holder.icon)
@ -352,8 +357,8 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
fun getActualItemViewType(position: Int): Int {
val cursor = super.getItem(position) as Cursor
if (cursor == null || mIndices == null) throw NullPointerException()
when (cursor.getString(mIndices!!.type)) {
if (indices == null) throw NullPointerException()
when (cursor.getString(indices!!.type)) {
Suggestions.Search.TYPE_SAVED_SEARCH -> {
return VIEW_TYPE_SAVED_SEARCH
}
@ -377,24 +382,20 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
override fun onClick(v: View) {
when (v.id) {
R.id.edit_query -> {
mActivity.setSearchQueryText(v.tag as String)
activity.setSearchQueryText(v.tag as String)
}
}
}
override fun swapCursor(newCursor: Cursor?): Cursor {
if (newCursor != null) {
mIndices = Indices(newCursor)
} else {
mIndices = null
}
mRemovedPositions!!.clear()
override fun swapCursor(newCursor: Cursor?): Cursor? {
indices = if (newCursor != null) Indices(newCursor) else null
removedPositions!!.clear()
return super.swapCursor(newCursor)
}
override fun getCount(): Int {
if (mRemovedPositions == null) return super.getCount()
return super.getCount() - mRemovedPositions.size()
if (removedPositions == null) return super.getCount()
return super.getCount() - removedPositions.size()
}
override fun getItem(position: Int): Any {
@ -405,21 +406,21 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
return super.getItemId(getActualPosition(position))
}
override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
return super.getView(getActualPosition(position), convertView, parent)
}
override fun getDropDownView(position: Int, convertView: View, parent: ViewGroup): View {
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
return super.getDropDownView(getActualPosition(position), convertView, parent)
}
private fun getActualPosition(position: Int): Int {
if (mRemovedPositions == null) return position
if (removedPositions == null) return position
var skipped = 0
var i = 0
val j = mRemovedPositions.size()
val j = removedPositions.size()
while (i < j) {
if (position + skipped >= mRemovedPositions.get(i)) {
if (position + skipped >= removedPositions.get(i)) {
skipped++
}
i++
@ -429,9 +430,9 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
fun addRemovedPositions(positions: IntArray) {
for (position in positions) {
mRemovedPositions!!.add(getActualPosition(position))
removedPositions!!.add(getActualPosition(position))
}
mRemovedPositions!!.sort()
removedPositions!!.sort()
notifyDataSetChanged()
}

View File

@ -70,62 +70,62 @@ import java.util.*
abstract class AbsActivitiesFragment protected constructor() : AbsContentListRecyclerViewFragment<ParcelableActivitiesAdapter>(), LoaderCallbacks<List<ParcelableActivity>>, ParcelableActivitiesAdapter.ActivityAdapterListener, KeyboardShortcutCallback {
private val mStatusesBusCallback: Any
private val mHotMobiScrollTracker = object : OnScrollListener() {
private val statusesBusCallback: Any
private val hotMobiScrollTracker = object : OnScrollListener() {
var mRecords: MutableList<ScrollRecord>? = null
private var mFirstVisibleTimestamp: Long = -1
private var mFirstVisibleAccountId: UserKey? = null
private var mFirstVisiblePosition = -1
private var mScrollState: Int = 0
var records: MutableList<ScrollRecord>? = null
private var firstVisibleTimestamp: Long = -1
private var firstVisibleAccountId: UserKey? = null
private var firstVisiblePosition = -1
private var scrollState: Int = 0
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
val layoutManager = recyclerView!!.layoutManager as LinearLayoutManager
val firstVisiblePosition = layoutManager.findFirstVisibleItemPosition()
if (firstVisiblePosition != mFirstVisiblePosition && firstVisiblePosition >= 0) {
val pos = layoutManager.findFirstVisibleItemPosition()
if (pos != firstVisiblePosition && pos >= 0) {
//noinspection unchecked
val adapter = recyclerView.adapter as ParcelableActivitiesAdapter
val activity = adapter.getActivity(firstVisiblePosition)
val activity = adapter.getActivity(pos)
if (activity != null) {
val timestamp = activity.timestamp
val accountKey = activity.account_key
if (timestamp != mFirstVisibleTimestamp || accountKey != mFirstVisibleAccountId) {
if (mRecords == null) mRecords = ArrayList<ScrollRecord>()
if (timestamp != firstVisibleTimestamp || accountKey != firstVisibleAccountId) {
if (records == null) records = ArrayList<ScrollRecord>()
val time = System.currentTimeMillis()
mRecords!!.add(ScrollRecord.create(timestamp.toString(), accountKey, time,
TimeZone.getDefault().getOffset(time).toLong(), mScrollState))
records!!.add(ScrollRecord.create(timestamp.toString(), accountKey, time,
TimeZone.getDefault().getOffset(time).toLong(), scrollState))
}
mFirstVisibleTimestamp = timestamp
mFirstVisibleAccountId = accountKey
firstVisibleTimestamp = timestamp
firstVisibleAccountId = accountKey
}
}
mFirstVisiblePosition = firstVisiblePosition
firstVisiblePosition = pos
}
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
mScrollState = newState
scrollState = newState
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (mRecords != null) {
HotMobiLogger.getInstance(activity).logList(mRecords, null, "scroll")
if (records != null) {
HotMobiLogger.getInstance(activity).logList(records, null, "scroll")
}
mRecords = null
records = null
}
}
}
private val mOnScrollListener = object : OnScrollListener() {
private val onScrollListener = object : OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
saveReadPosition()
}
}
}
private var mNavigationHelper: RecyclerViewNavigationHelper? = null
private var mPauseOnScrollListener: OnScrollListener? = null
private var mActiveHotMobiScrollTracker: OnScrollListener? = null
private var navigationHelper: RecyclerViewNavigationHelper? = null
private var pauseOnScrollListener: OnScrollListener? = null
private var activeHotMobiScrollTracker: OnScrollListener? = null
init {
mStatusesBusCallback = createMessageBusCallback()
statusesBusCallback = createMessageBusCallback()
}
abstract fun getActivities(param: RefreshTaskParam): Boolean
@ -178,7 +178,7 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
}
}
}
return mNavigationHelper!!.handleKeyboardShortcutSingle(handler, keyCode, event, metaState)
return navigationHelper!!.handleKeyboardShortcutSingle(handler, keyCode, event, metaState)
}
private fun openActivity(activity: ParcelableActivity) {
@ -200,12 +200,12 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
when (action) {
ACTION_STATUS_REPLY, ACTION_STATUS_RETWEET, ACTION_STATUS_FAVORITE -> return true
}
return mNavigationHelper!!.isKeyboardShortcutHandled(handler, keyCode, event, metaState)
return navigationHelper!!.isKeyboardShortcutHandled(handler, keyCode, event, metaState)
}
override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler, keyCode: Int, repeatCount: Int,
event: KeyEvent, metaState: Int): Boolean {
return mNavigationHelper!!.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)
return navigationHelper!!.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<List<ParcelableActivity>> {
@ -381,8 +381,8 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
override fun onStart() {
super.onStart()
recyclerView.addOnScrollListener(mOnScrollListener)
recyclerView.addOnScrollListener(mPauseOnScrollListener)
recyclerView.addOnScrollListener(onScrollListener)
recyclerView.addOnScrollListener(pauseOnScrollListener)
val task = object : AbstractTask<Any?, Boolean, RecyclerView>() {
public override fun doLongOperation(params: Any?): Boolean {
val context = context ?: return false
@ -395,24 +395,24 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
public override fun afterExecute(recyclerView: RecyclerView?, result: Boolean?) {
if (result!!) {
mActiveHotMobiScrollTracker = mHotMobiScrollTracker
recyclerView!!.addOnScrollListener(mActiveHotMobiScrollTracker)
activeHotMobiScrollTracker = hotMobiScrollTracker
recyclerView!!.addOnScrollListener(activeHotMobiScrollTracker)
}
}
}
task.setCallback(recyclerView)
TaskStarter.execute(task)
bus.register(mStatusesBusCallback)
bus.register(statusesBusCallback)
}
override fun onStop() {
bus.unregister(mStatusesBusCallback)
if (mActiveHotMobiScrollTracker != null) {
recyclerView.removeOnScrollListener(mActiveHotMobiScrollTracker)
bus.unregister(statusesBusCallback)
if (activeHotMobiScrollTracker != null) {
recyclerView.removeOnScrollListener(activeHotMobiScrollTracker)
}
mActiveHotMobiScrollTracker = null
recyclerView.removeOnScrollListener(mPauseOnScrollListener)
recyclerView.removeOnScrollListener(mOnScrollListener)
activeHotMobiScrollTracker = null
recyclerView.removeOnScrollListener(pauseOnScrollListener)
recyclerView.removeOnScrollListener(onScrollListener)
if (userVisibleHint) {
saveReadPosition()
}
@ -438,9 +438,9 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
val layoutManager = layoutManager
adapter!!.setListener(this)
registerForContextMenu(recyclerView)
mNavigationHelper = RecyclerViewNavigationHelper(recyclerView, layoutManager!!, adapter,
navigationHelper = RecyclerViewNavigationHelper(recyclerView, layoutManager!!, adapter,
this)
mPauseOnScrollListener = PauseRecyclerViewOnScrollListener(adapter.mediaLoader.imageLoader, false, true)
pauseOnScrollListener = PauseRecyclerViewOnScrollListener(adapter.mediaLoader.imageLoader, false, true)
val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(IntentConstants.EXTRA_FROM_USER, true)

View File

@ -115,11 +115,12 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
return false
}
override fun getCurrentVisibleFragment(): Fragment? {
val currentItem = viewPager.currentItem
if (currentItem < 0 || currentItem >= pagerAdapter!!.count) return null
return pagerAdapter!!.instantiateItem(viewPager, currentItem) as Fragment
}
override val currentVisibleFragment: Fragment?
get() {
val currentItem = viewPager.currentItem
if (currentItem < 0 || currentItem >= pagerAdapter!!.count) return null
return pagerAdapter!!.instantiateItem(viewPager, currentItem) as Fragment
}
override fun triggerRefresh(position: Int): Boolean {
return false

View File

@ -0,0 +1,46 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.os.Bundle
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.SharedPreferenceConstants.*
class AccountNotificationSettingsFragment : BaseAccountPreferenceFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val preference = findPreference(KEY_NOTIFICATION_LIGHT_COLOR)
val account = account
if (preference != null && account != null) {
preference.setDefaultValue(account.color)
}
}
override val preferencesResource: Int
get() = R.xml.preferences_account_notifications
override val switchPreferenceDefault: Boolean
get() = DEFAULT_NOTIFICATION
override val switchPreferenceKey: String?
get() = KEY_NOTIFICATION
}

View File

@ -0,0 +1,48 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Activity
import android.content.SharedPreferences
import org.mariotaku.twidere.R
import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.constant.SharedPreferenceConstants.DEFAULT_AUTO_REFRESH
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_AUTO_REFRESH
class AccountRefreshSettingsFragment : BaseAccountPreferenceFragment() {
override val preferencesResource: Int
get() = R.xml.preferences_account_refresh
override val switchPreferenceDefault: Boolean
get() = DEFAULT_AUTO_REFRESH
override val switchPreferenceKey: String?
get() = null
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
val activity = activity ?: return
if (KEY_AUTO_REFRESH == key) {
Utils.startRefreshServiceIfNeeded(activity)
}
}
}

View File

@ -268,7 +268,7 @@ class AccountsDashboardFragment : BaseSupportFragment(), LoaderCallbacks<Cursor>
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
if (KEY_DEFAULT_ACCOUNT_KEY == key) {
updateDefaultAccountState()
}

View File

@ -0,0 +1,116 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Bundle
import android.preference.PreferenceActivity.EXTRA_SHOW_FRAGMENT
import android.text.TextUtils
import android.view.Menu
import android.view.MenuInflater
import android.widget.CompoundButton
import android.widget.CompoundButton.OnCheckedChangeListener
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.ACCOUNT_PREFERENCES_NAME_PREFIX
import org.mariotaku.twidere.constant.IntentConstants
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NAME_FIRST
import org.mariotaku.twidere.model.ParcelableAccount
abstract class BaseAccountPreferenceFragment : BasePreferenceFragment(), OnCheckedChangeListener, OnSharedPreferenceChangeListener {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
val pm = preferenceManager
val account = arguments.getParcelable<ParcelableAccount>(IntentConstants.EXTRA_ACCOUNT) ?: return
val preferenceName = "$ACCOUNT_PREFERENCES_NAME_PREFIX${account.account_key}"
pm.sharedPreferencesName = preferenceName
addPreferencesFromResource(preferencesResource)
val prefs = pm.sharedPreferences
prefs.registerOnSharedPreferenceChangeListener(this)
val activity = activity
val intent = activity.intent
if (intent.hasExtra(EXTRA_SHOW_FRAGMENT)) {
val nameFirst = prefs.getBoolean(KEY_NAME_FIRST, true)
val name = userColorNameManager.getDisplayName(account.account_key,
account.name, account.screen_name, nameFirst)
activity.title = name
}
updatePreferenceScreen()
}
override fun onDestroy() {
val pm = preferenceManager
val prefs = pm.sharedPreferences
prefs.unregisterOnSharedPreferenceChangeListener(this)
super.onDestroy()
}
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
val prefs = preferenceManager.sharedPreferences
val editor = prefs.edit()
if (prefs.getBoolean(switchPreferenceKey, switchPreferenceDefault) != isChecked) {
editor.putBoolean(switchPreferenceKey, isChecked)
editor.apply()
}
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
val switchKey = switchPreferenceKey
if (!TextUtils.isEmpty(switchKey)) {
inflater!!.inflate(R.menu.menu_switch_preference, menu)
val actionView = menu!!.findItem(R.id.toggle).actionView
val toggle = actionView.findViewById(android.R.id.toggle) as CompoundButton
val prefs = preferenceManager.sharedPreferences
toggle.setOnCheckedChangeListener(this)
toggle.isChecked = prefs.getBoolean(switchKey, switchPreferenceDefault)
}
super.onCreateOptionsMenu(menu, inflater)
}
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
if (key == switchPreferenceKey) {
updatePreferenceScreen()
}
}
protected val account: ParcelableAccount?
get() {
val args = arguments ?: return null
return args.getParcelable<ParcelableAccount>(IntentConstants.EXTRA_ACCOUNT)
}
protected abstract val preferencesResource: Int
protected abstract val switchPreferenceDefault: Boolean
protected abstract val switchPreferenceKey: String?
private fun updatePreferenceScreen() {
val screen = preferenceScreen
val sharedPreferences = preferenceManager.sharedPreferences
if (screen == null || sharedPreferences == null) return
screen.isEnabled = sharedPreferences.getBoolean(switchPreferenceKey, switchPreferenceDefault)
}
}

View File

@ -0,0 +1,115 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.media.RingtoneManager
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.support.v7.preference.Preference
import android.support.v7.preference.PreferenceFragmentCompat
import org.mariotaku.twidere.preference.RingtonePreference
import org.mariotaku.twidere.util.KeyboardShortcutsHandler
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import javax.inject.Inject
abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
private var ringtonePreferenceKey: String? = null
@Inject
lateinit var keyboardShortcutHandler: KeyboardShortcutsHandler
@Inject
lateinit var userColorNameManager: UserColorNameManager
override fun onAttach(context: Context) {
super.onAttach(context)
GeneralComponentHelper.build(context).inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
if (savedInstanceState != null) {
ringtonePreferenceKey = savedInstanceState.getString(EXTRA_RINGTONE_PREFERENCE_KEY)
}
super.onActivityCreated(savedInstanceState)
}
override fun onSaveInstanceState(outState: Bundle?) {
outState!!.putString(EXTRA_RINGTONE_PREFERENCE_KEY, ringtonePreferenceKey)
super.onSaveInstanceState(outState)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_PICK_RINGTONE -> {
if (resultCode == Activity.RESULT_OK && data != null) {
val ringtone = data.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
if (ringtonePreferenceKey != null) {
val ringtonePreference = findPreference(ringtonePreferenceKey) as RingtonePreference?
if (ringtonePreference != null) {
ringtonePreference.value = ringtone?.toString()
}
}
ringtonePreferenceKey = null
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
if (preference is RingtonePreference) {
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, preference.ringtoneType)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, preference.isShowDefault)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, preference.isShowSilent)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI)
val existingValue = preference.value // TODO
if (existingValue != null) {
if (existingValue.length == 0) {
// Select "Silent"
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, null as Uri)
} else {
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(existingValue))
}
} else {
// No ringtone has been selected, set to the default
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Settings.System.DEFAULT_NOTIFICATION_URI)
}
startActivityForResult(intent, REQUEST_PICK_RINGTONE)
ringtonePreferenceKey = preference.key
return true
}
return super.onPreferenceTreeClick(preference)
}
companion object {
private val REQUEST_PICK_RINGTONE = 301
private val EXTRA_RINGTONE_PREFERENCE_KEY = "internal:ringtone_preference_key"
}
}

View File

@ -26,14 +26,13 @@ import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.text.BidiFormatter
import com.squareup.otto.Bus
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.constant.IntentConstants
import org.mariotaku.twidere.fragment.iface.IBaseFragment
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import javax.inject.Inject
open class BaseSupportFragment : Fragment(), IBaseFragment, Constants {
open class BaseSupportFragment : Fragment(), IBaseFragment {
// Utility classes
@Inject
@ -83,14 +82,16 @@ open class BaseSupportFragment : Fragment(), IBaseFragment, Constants {
activity.supportInvalidateOptionsMenu()
}
override fun getExtraConfiguration(): Bundle? {
return null
}
override val extraConfiguration: Bundle?
get() {
return null
}
override fun getTabPosition(): Int {
val args = arguments
return if (args != null) args.getInt(IntentConstants.EXTRA_TAB_POSITION, -1) else -1
}
override val tabPosition: Int
get() {
val args = arguments
return if (args != null) args.getInt(IntentConstants.EXTRA_TAB_POSITION, -1) else -1
}
override fun requestFitSystemWindows() {
val activity = activity
@ -109,7 +110,7 @@ open class BaseSupportFragment : Fragment(), IBaseFragment, Constants {
}
}
override fun executeAfterFragmentResumed(action: IBaseFragment.Action) {
override fun executeAfterFragmentResumed(action: (IBaseFragment) -> Unit) {
actionHelper.executeAfterFragmentResumed(action)
}
@ -118,6 +119,11 @@ open class BaseSupportFragment : Fragment(), IBaseFragment, Constants {
actionHelper.dispatchOnResumeFragments()
}
override fun onPause() {
actionHelper.dispatchOnPause()
super.onPause()
}
override fun onDestroy() {
super.onDestroy()
DebugModeUtils.watchReferenceLeak(this)

View File

@ -0,0 +1,105 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.webkit.WebViewClient
import org.mariotaku.twidere.util.support.WebSettingsSupport
import org.mariotaku.twidere.util.webkit.DefaultWebViewClient
@SuppressLint("SetJavaScriptEnabled")
open class BaseSupportWebViewFragment : BaseSupportFragment() {
private var internalWebView: WebView? = null
private var webViewAvailable: Boolean = false
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val view = webView
view!!.setWebViewClient(createWebViewClient())
val settings = view.settings
settings.builtInZoomControls = true
settings.javaScriptEnabled = true
WebSettingsSupport.setAllowUniversalAccessFromFileURLs(settings, true)
}
protected fun createWebViewClient(): WebViewClient {
return DefaultWebViewClient(activity)
}
/**
* Called to instantiate the view. Creates and returns the WebView.
*/
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
internalWebView?.destroy()
internalWebView = WebView(activity)
webViewAvailable = true
return internalWebView
}
/**
* Called when the fragment is visible to the user and actively running. Resumes the WebView.
*/
override fun onPause() {
super.onPause()
internalWebView!!.onPause()
}
/**
* Called when the fragment is no longer resumed. Pauses the WebView.
*/
override fun onResume() {
internalWebView!!.onResume()
super.onResume()
}
/**
* Called when the WebView has been detached from the fragment.
* The WebView is no longer available after this time.
*/
override fun onDestroyView() {
webViewAvailable = false
super.onDestroyView()
}
/**
* Called when the fragment is no longer in use. Destroys the internal state of the WebView.
*/
override fun onDestroy() {
if (internalWebView != null) {
internalWebView!!.destroy()
internalWebView = null
}
super.onDestroy()
}
/**
* Gets the WebView.
*/
val webView: WebView?
get() = if (webViewAvailable) internalWebView else null
}

View File

@ -66,7 +66,7 @@ import java.util.*
class DirectMessagesFragment : AbsContentListRecyclerViewFragment<MessageEntriesAdapter>(), LoaderCallbacks<Cursor>, MessageEntriesAdapterListener, KeyboardShortcutCallback {
// Listeners
private val mReloadContentObserver = SupportFragmentReloadCursorObserver(
private val reloadContentObserver = SupportFragmentReloadCursorObserver(
this, 0, this)
private var mRemoveUnreadCountsTask: RemoveUnreadCountsTask? = null
@ -82,10 +82,9 @@ class DirectMessagesFragment : AbsContentListRecyclerViewFragment<MessageEntries
}
fun onLoadMoreContents(@IndicatorPosition position: Int) {
var position = position
// Only supports load from end, so remove START flag
position = position and ILoadMoreSupportAdapter.START.inv().toInt()
if (position == 0) return
val pos = position and ILoadMoreSupportAdapter.START.inv().toInt()
if (pos == 0) return
loadMoreMessages()
}
@ -236,8 +235,7 @@ class DirectMessagesFragment : AbsContentListRecyclerViewFragment<MessageEntries
override fun onStart() {
super.onStart()
val resolver = contentResolver
resolver!!.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver)
contentResolver.registerContentObserver(Accounts.CONTENT_URI, true, reloadContentObserver)
bus.register(this)
val adapter = adapter
adapter!!.updateReadState()
@ -246,8 +244,7 @@ class DirectMessagesFragment : AbsContentListRecyclerViewFragment<MessageEntries
override fun onStop() {
bus.unregister(this)
val resolver = contentResolver
resolver!!.unregisterContentObserver(mReloadContentObserver)
contentResolver.unregisterContentObserver(reloadContentObserver)
super.onStop()
}

View File

@ -17,31 +17,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
package org.mariotaku.twidere.fragment
import android.os.Bundle;
import android.os.Bundle
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.SupportTabsAdapter;
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredKeywordsFragment;
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredLinksFragment;
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredSourcesFragment;
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredUsersFragment;
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.SupportTabsAdapter
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredKeywordsFragment
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredLinksFragment
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredSourcesFragment
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredUsersFragment
public class FiltersFragment extends AbsToolbarTabPagesFragment {
class FiltersFragment : AbsToolbarTabPagesFragment() {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
}
@Override
protected void addTabs(SupportTabsAdapter adapter) {
adapter.addTab(FilteredUsersFragment.class, null, getString(R.string.users), null, 0, null);
adapter.addTab(FilteredKeywordsFragment.class, null, getString(R.string.keywords), null, 1, null);
adapter.addTab(FilteredSourcesFragment.class, null, getString(R.string.sources), null, 2, null);
adapter.addTab(FilteredLinksFragment.class, null, getString(R.string.links), null, 3, null);
override fun addTabs(adapter: SupportTabsAdapter) {
adapter.addTab(FilteredUsersFragment::class.java, null, getString(R.string.users), null, 0, null)
adapter.addTab(FilteredKeywordsFragment::class.java, null, getString(R.string.keywords), null, 1, null)
adapter.addTab(FilteredSourcesFragment::class.java, null, getString(R.string.sources), null, 2, null)
adapter.addTab(FilteredLinksFragment::class.java, null, getString(R.string.links), null, 3, null)
}
}

View File

@ -0,0 +1,143 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.graphics.Rect
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_LATITUDE
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_LONGITUDE
import org.mariotaku.twidere.fragment.iface.IBaseFragment
import org.mariotaku.twidere.fragment.iface.IMapFragment
class GoogleMapFragment : SupportMapFragment(), Constants, IMapFragment, IBaseFragment {
private val actionHelper = IBaseFragment.ActionHelper(this)
private var activeMap: GoogleMap? = null
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
val args = arguments
if (args == null || !args.containsKey(EXTRA_LATITUDE) || !args.containsKey(EXTRA_LONGITUDE))
return
val lat = args.getDouble(EXTRA_LATITUDE, 0.0)
val lng = args.getDouble(EXTRA_LONGITUDE, 0.0)
getMapAsync { googleMap ->
val marker = MarkerOptions()
marker.position(LatLng(lat, lng))
googleMap.addMarker(marker)
center(false)
activeMap = googleMap
}
}
override fun onPause() {
actionHelper.dispatchOnPause()
super.onPause()
}
override fun onResume() {
super.onResume()
actionHelper.dispatchOnResumeFragments()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_google_maps_viewer, menu)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requestFitSystemWindows()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.center -> {
center()
}
}
return true
}
override fun center() {
center(true)
}
fun center(animate: Boolean) {
val googleMap = activeMap ?: return
val args = arguments ?: return
if (!args.containsKey(EXTRA_LATITUDE) || !args.containsKey(EXTRA_LONGITUDE))
return
val lat = args.getDouble(EXTRA_LATITUDE, 0.0)
val lng = args.getDouble(EXTRA_LONGITUDE, 0.0)
val c = CameraUpdateFactory.newLatLngZoom(LatLng(lat, lng), 12f)
if (animate) {
googleMap.animateCamera(c)
} else {
googleMap.moveCamera(c)
}
}
override val extraConfiguration: Bundle?
get() = null
override val tabPosition: Int
get() = 0
override fun requestFitSystemWindows() {
val activity = activity
val parentFragment = parentFragment
val callback: IBaseFragment.SystemWindowsInsetsCallback
if (parentFragment is IBaseFragment.SystemWindowsInsetsCallback) {
callback = parentFragment
} else if (activity is IBaseFragment.SystemWindowsInsetsCallback) {
callback = activity
} else {
return
}
val insets = Rect()
if (callback.getSystemWindowsInsets(insets)) {
fitSystemWindows(insets)
}
}
override fun executeAfterFragmentResumed(action: (IBaseFragment) -> Unit) {
actionHelper.executeAfterFragmentResumed(action)
}
protected fun fitSystemWindows(insets: Rect) {
val view = view
view?.setPadding(insets.left, insets.top, insets.right, insets.bottom)
}
}

View File

@ -0,0 +1,131 @@
package org.mariotaku.twidere.fragment
import android.content.Context
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter
import android.os.Bundle
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.AsyncTaskLoader
import android.support.v4.content.Loader
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.statusnet.model.Group
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.SupportTabsAdapter
import org.mariotaku.twidere.model.ParcelableGroup
import org.mariotaku.twidere.model.SingleResponse
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.ParcelableGroupUtils
import org.mariotaku.twidere.util.MicroBlogAPIFactory
import org.mariotaku.twidere.util.Utils
/**
* Created by mariotaku on 16/3/23.
*/
class GroupFragment : AbsToolbarTabPagesFragment(), LoaderCallbacks<SingleResponse<ParcelableGroup>> {
var group: ParcelableGroup? = null
private set
private var groupLoaderInitialized: Boolean = false
override fun addTabs(adapter: SupportTabsAdapter) {
val args = arguments
adapter.addTab(GroupTimelineFragment::class.java, args, getString(R.string.statuses), 0, 0, "statuses")
adapter.addTab(GroupMembersFragment::class.java, args, getString(R.string.members), 0, 1, "members")
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Utils.setNdefPushMessageCallback(activity, NfcAdapter.CreateNdefMessageCallback {
val url = group?.url ?: return@CreateNdefMessageCallback null
NdefMessage(arrayOf(NdefRecord.createUri(url)))
})
getGroupInfo(false)
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<SingleResponse<ParcelableGroup>> {
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val groupId = args.getString(EXTRA_GROUP_ID)
val groupName = args.getString(EXTRA_GROUP_NAME)
val omitIntentExtra = args.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true)
return ParcelableGroupLoader(context, omitIntentExtra, arguments, accountKey,
groupId, groupName)
}
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableGroup>>, data: SingleResponse<ParcelableGroup>) {
if (data.hasData()) {
displayGroup(data.data)
}
}
override fun onLoaderReset(loader: Loader<SingleResponse<ParcelableGroup>>) {
}
fun displayGroup(group: ParcelableGroup?) {
val activity = activity ?: return
loaderManager.destroyLoader(0)
this.group = group
if (group != null) {
activity.title = group.fullname
} else {
activity.setTitle(R.string.user_list)
}
invalidateOptionsMenu()
}
fun getGroupInfo(omitIntentExtra: Boolean) {
val lm = loaderManager
lm.destroyLoader(0)
val args = Bundle(arguments)
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra)
if (!groupLoaderInitialized) {
lm.initLoader(0, args, this)
groupLoaderInitialized = true
} else {
lm.restartLoader(0, args, this)
}
}
internal class ParcelableGroupLoader(
context: Context,
private val omitIntentExtra: Boolean,
private val extras: Bundle?,
private val accountKey: UserKey,
private val groupId: String?,
private val groupName: String?
) : AsyncTaskLoader<SingleResponse<ParcelableGroup>>(context) {
override fun loadInBackground(): SingleResponse<ParcelableGroup> {
if (!omitIntentExtra && extras != null) {
val cache = extras.getParcelable<ParcelableGroup>(EXTRA_GROUP)
if (cache != null) return SingleResponse.getInstance(cache)
}
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey,
true) ?: return SingleResponse.getInstance<ParcelableGroup>()
try {
val group: Group
if (groupId != null) {
group = twitter.showGroup(groupId)
} else if (groupName != null) {
group = twitter.showGroupByName(groupName)
} else {
return SingleResponse.getInstance<ParcelableGroup>()
}
return SingleResponse.getInstance(ParcelableGroupUtils.from(group, accountKey, 0,
group.isMember))
} catch (e: MicroBlogException) {
return SingleResponse.getInstance<ParcelableGroup>(e)
}
}
public override fun onStartLoading() {
forceLoad()
}
}
}

View File

@ -130,7 +130,7 @@ class HostMappingsListFragment : BaseListFragment(), MultiChoiceModeListener, On
updateTitle(mode)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
reloadHostMappings()
}

View File

@ -0,0 +1,16 @@
package org.mariotaku.twidere.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.mariotaku.twidere.R
class InvalidTabFragment : BaseSupportFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_invalid_tab, container, false)
}
}

Some files were not shown because too many files have changed in this diff Show More