diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index 5faf0c1d0..a6cf2d65d 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -1,5 +1,6 @@ package fr.free.nrw.commons; +import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; @@ -18,15 +19,12 @@ import java.io.File; import javax.inject.Inject; import javax.inject.Named; -import dagger.android.AndroidInjector; -import dagger.android.DaggerApplication; import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.category.CategoryDao; import fr.free.nrw.commons.contributions.ContributionDao; import fr.free.nrw.commons.data.DBOpenHelper; +import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.di.CommonsApplicationComponent; -import fr.free.nrw.commons.di.CommonsApplicationModule; -import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent; import fr.free.nrw.commons.modifications.ModifierSequenceDao; import fr.free.nrw.commons.utils.FileUtils; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -42,10 +40,11 @@ import timber.log.Timber; resDialogCommentPrompt = R.string.crash_dialog_comment_prompt, resDialogOkToast = R.string.crash_dialog_ok_toast ) -public class CommonsApplication extends DaggerApplication { +public class CommonsApplication extends Application { @Inject SessionManager sessionManager; @Inject DBOpenHelper dbOpenHelper; + @Inject @Named("default_preferences") SharedPreferences defaultPrefs; @Inject @Named("application_preferences") SharedPreferences applicationPrefs; @Inject @Named("prefs") SharedPreferences otherPrefs; @@ -61,6 +60,7 @@ public class CommonsApplication extends DaggerApplication { private CommonsApplicationComponent component; private RefWatcher refWatcher; + /** * Used to declare and initialize various components and dependencies */ @@ -68,6 +68,11 @@ public class CommonsApplication extends DaggerApplication { public void onCreate() { super.onCreate(); + ApplicationlessInjection + .getInstance(this) + .getCommonsApplicationComponent() + .inject(this); + Fresco.initialize(this); if (setupLeakCanary() == RefWatcher.DISABLED) { return; @@ -85,6 +90,7 @@ public class CommonsApplication extends DaggerApplication { System.setProperty("in.yuvi.http.fluent.PROGRESS_TRIGGER_THRESHOLD", "3.0"); } + /** * Helps in setting up LeakCanary library * @return instance of LeakCanary @@ -107,28 +113,6 @@ public class CommonsApplication extends DaggerApplication { return application.refWatcher; } - /** - * Helps in injecting dependency library Dagger - * @return Dagger injector - */ - @Override - protected AndroidInjector applicationInjector() { - return injector(); - } - - /** - * used to create injector of application component - * @return Application component of Dagger - */ - public CommonsApplicationComponent injector() { - if (component == null) { - component = DaggerCommonsApplicationComponent.builder() - .appModule(new CommonsApplicationModule(this)) - .build(); - } - return component; - } - /** * clears data of current application * @param context Application context diff --git a/app/src/main/java/fr/free/nrw/commons/HandlerService.java b/app/src/main/java/fr/free/nrw/commons/HandlerService.java index 69a1ea4b9..e5e1b3b1b 100644 --- a/app/src/main/java/fr/free/nrw/commons/HandlerService.java +++ b/app/src/main/java/fr/free/nrw/commons/HandlerService.java @@ -8,9 +8,9 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; -import dagger.android.DaggerService; +import fr.free.nrw.commons.di.CommonsDaggerService; -public abstract class HandlerService extends DaggerService { +public abstract class HandlerService extends CommonsDaggerService { private volatile Looper threadLooper; private volatile ServiceHandler threadHandler; private String serviceName; diff --git a/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java b/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java index 03fee8852..35d197782 100644 --- a/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java +++ b/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java @@ -14,6 +14,7 @@ import com.facebook.drawee.view.SimpleDraweeView; import javax.inject.Inject; +import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.mwapi.MediaWikiApi; import timber.log.Timber; @@ -71,7 +72,11 @@ public class MediaWikiImageView extends SimpleDraweeView { * Initializes MediaWikiImageView. */ private void init() { - ((CommonsApplication) getContext().getApplicationContext()).injector().inject(this); + ApplicationlessInjection + .getInstance(getContext() + .getApplicationContext()) + .getCommonsApplicationComponent() + .inject(this); setHierarchy(GenericDraweeHierarchyBuilder .newInstance(getResources()) .setPlaceholderImage(VectorDrawableCompat.create(getResources(), diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index d17120106..780f4310b 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -33,6 +33,7 @@ import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.WelcomeActivity; import fr.free.nrw.commons.contributions.ContributionsActivity; +import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.theme.NavigationBaseActivity; import timber.log.Timber; @@ -66,8 +67,12 @@ public class LoginActivity extends AccountAuthenticatorActivity { setTheme(Utils.isDarkTheme(this) ? R.style.DarkAppTheme : R.style.LightAppTheme); getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); - AndroidInjection.inject(this); + super.onCreate(savedInstanceState); + ApplicationlessInjection + .getInstance(this.getApplicationContext()) + .getCommonsApplicationComponent() + .inject(this); setContentView(R.layout.activity_login); diff --git a/app/src/main/java/fr/free/nrw/commons/auth/WikiAccountAuthenticatorService.java b/app/src/main/java/fr/free/nrw/commons/auth/WikiAccountAuthenticatorService.java index b0f3e6063..6bc6de076 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/WikiAccountAuthenticatorService.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/WikiAccountAuthenticatorService.java @@ -5,12 +5,12 @@ import android.os.IBinder; import javax.inject.Inject; -import dagger.android.DaggerService; +import fr.free.nrw.commons.di.CommonsDaggerService; import fr.free.nrw.commons.mwapi.MediaWikiApi; import static android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT; -public class WikiAccountAuthenticatorService extends DaggerService { +public class WikiAccountAuthenticatorService extends CommonsDaggerService { @Inject MediaWikiApi mwApi; private WikiAccountAuthenticator wikiAccountAuthenticator = null; diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java index 4787d0e4f..76a70c0b3 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java @@ -1,5 +1,6 @@ package fr.free.nrw.commons.category; +import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AlertDialog; @@ -33,8 +34,8 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; -import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.upload.MwVolleyApi; import fr.free.nrw.commons.utils.StringSortingUtils; @@ -49,7 +50,7 @@ import static android.view.KeyEvent.KEYCODE_BACK; /** * Displays the category suggestion and selection screen. Category search is initiated here. */ -public class CategorizationFragment extends DaggerFragment { +public class CategorizationFragment extends CommonsDaggerSupportFragment { public static final int SEARCH_CATS_LIMIT = 25; @@ -134,11 +135,6 @@ public class CategorizationFragment extends DaggerFragment { } } - @Override - public void onDestroy() { - super.onDestroy(); - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryContentProvider.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryContentProvider.java index dcc1bc6f2..16cf49742 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryContentProvider.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryContentProvider.java @@ -1,6 +1,5 @@ package fr.free.nrw.commons.category; -import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; @@ -12,8 +11,8 @@ import android.text.TextUtils; import javax.inject.Inject; -import dagger.android.AndroidInjection; import fr.free.nrw.commons.data.DBOpenHelper; +import fr.free.nrw.commons.di.CommonsDaggerContentProvider; import timber.log.Timber; import static android.content.UriMatcher.NO_MATCH; @@ -21,7 +20,7 @@ import static fr.free.nrw.commons.category.CategoryDao.Table.ALL_FIELDS; import static fr.free.nrw.commons.category.CategoryDao.Table.COLUMN_ID; import static fr.free.nrw.commons.category.CategoryDao.Table.TABLE_NAME; -public class CategoryContentProvider extends ContentProvider { +public class CategoryContentProvider extends CommonsDaggerContentProvider { public static final String AUTHORITY = "fr.free.nrw.commons.categories.contentprovider"; // For URI matcher @@ -44,12 +43,6 @@ public class CategoryContentProvider extends ContentProvider { @Inject DBOpenHelper dbOpenHelper; - @Override - public boolean onCreate() { - AndroidInjection.inject(this); - return false; - } - @SuppressWarnings("ConstantConditions") @Override public Cursor query(@NonNull Uri uri, String[] projection, String selection, diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java index 4d82bdfb1..7dc750732 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java @@ -1,6 +1,5 @@ package fr.free.nrw.commons.contributions; -import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; @@ -12,15 +11,15 @@ import android.text.TextUtils; import javax.inject.Inject; -import dagger.android.AndroidInjection; import fr.free.nrw.commons.data.DBOpenHelper; +import fr.free.nrw.commons.di.CommonsDaggerContentProvider; import timber.log.Timber; import static android.content.UriMatcher.NO_MATCH; import static fr.free.nrw.commons.contributions.ContributionDao.Table.ALL_FIELDS; import static fr.free.nrw.commons.contributions.ContributionDao.Table.TABLE_NAME; -public class ContributionsContentProvider extends ContentProvider { +public class ContributionsContentProvider extends CommonsDaggerContentProvider { private static final int CONTRIBUTIONS = 1; private static final int CONTRIBUTIONS_ID = 2; @@ -41,12 +40,6 @@ public class ContributionsContentProvider extends ContentProvider { @Inject DBOpenHelper dbOpenHelper; - @Override - public boolean onCreate() { - AndroidInjection.inject(this); - return true; - } - @SuppressWarnings("ConstantConditions") @Override public Cursor query(@NonNull Uri uri, String[] projection, String selection, diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index 590d4e6ad..3a391b293 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -25,8 +25,8 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; -import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.nearby.NearbyActivity; import timber.log.Timber; @@ -36,7 +36,7 @@ import static android.app.Activity.RESULT_OK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.view.View.GONE; -public class ContributionsListFragment extends DaggerFragment { +public class ContributionsListFragment extends CommonsDaggerSupportFragment { @BindView(R.id.contributionsList) GridView contributionsList; diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java index f8245032b..5be634a2e 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java @@ -25,6 +25,7 @@ import javax.inject.Named; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.mwapi.LogEventResult; import fr.free.nrw.commons.mwapi.MediaWikiApi; import timber.log.Timber; @@ -81,7 +82,11 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { @Override public void onPerformSync(Account account, Bundle bundle, String authority, ContentProviderClient contentProviderClient, SyncResult syncResult) { - ((CommonsApplication) getContext().getApplicationContext()).injector().inject(this); + ApplicationlessInjection + .getInstance(getContext() + .getApplicationContext()) + .getCommonsApplicationComponent() + .inject(this); // This code is fraught with possibilities of race conditions, but lalalalala I can't hear you! String user = account.name; String lastModified = prefs.getString("lastSyncTimestamp", ""); diff --git a/app/src/main/java/fr/free/nrw/commons/di/ApplicationlessInjection.java b/app/src/main/java/fr/free/nrw/commons/di/ApplicationlessInjection.java new file mode 100644 index 000000000..2faf09b83 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/ApplicationlessInjection.java @@ -0,0 +1,93 @@ +package fr.free.nrw.commons.di; + +import android.app.Activity; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ContentProvider; +import android.content.Context; +import android.support.v4.app.Fragment; + +import javax.inject.Inject; + +import dagger.android.AndroidInjector; +import dagger.android.DispatchingAndroidInjector; +import dagger.android.HasActivityInjector; +import dagger.android.HasBroadcastReceiverInjector; +import dagger.android.HasContentProviderInjector; +import dagger.android.HasFragmentInjector; +import dagger.android.HasServiceInjector; +import dagger.android.support.HasSupportFragmentInjector; + +public class ApplicationlessInjection + implements + HasActivityInjector, + HasFragmentInjector, + HasSupportFragmentInjector, + HasServiceInjector, + HasBroadcastReceiverInjector, + HasContentProviderInjector { + + private static ApplicationlessInjection instance = null; + + @Inject DispatchingAndroidInjector activityInjector; + @Inject DispatchingAndroidInjector broadcastReceiverInjector; + @Inject DispatchingAndroidInjector fragmentInjector; + @Inject DispatchingAndroidInjector supportFragmentInjector; + @Inject DispatchingAndroidInjector serviceInjector; + @Inject DispatchingAndroidInjector contentProviderInjector; + + private CommonsApplicationComponent commonsApplicationComponent; + + public ApplicationlessInjection(Context applicationContext) { + commonsApplicationComponent = DaggerCommonsApplicationComponent.builder() + .appModule(new CommonsApplicationModule(applicationContext)).build(); + commonsApplicationComponent.inject(this); + } + + @Override + public DispatchingAndroidInjector activityInjector() { + return activityInjector; + } + + @Override + public DispatchingAndroidInjector fragmentInjector() { + return fragmentInjector; + } + + @Override + public DispatchingAndroidInjector supportFragmentInjector() { + return supportFragmentInjector; + } + + @Override + public DispatchingAndroidInjector broadcastReceiverInjector() { + return broadcastReceiverInjector; + } + + @Override + public DispatchingAndroidInjector serviceInjector() { + return serviceInjector; + } + + @Override + public AndroidInjector contentProviderInjector() { + return contentProviderInjector; + } + + public CommonsApplicationComponent getCommonsApplicationComponent() { + return commonsApplicationComponent; + } + + public static ApplicationlessInjection getInstance(Context applicationContext) { + if (instance == null) { + synchronized (ApplicationlessInjection.class) { + if (instance == null) { + instance = new ApplicationlessInjection(applicationContext); + } + } + } + + return instance; + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index 2881f33fd..14985c6b6 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -1,5 +1,7 @@ package fr.free.nrw.commons.di; +import android.content.Context; + import javax.inject.Singleton; import dagger.Component; @@ -8,8 +10,13 @@ import dagger.android.AndroidInjector; import dagger.android.support.AndroidSupportInjectionModule; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.MediaWikiImageView; +import fr.free.nrw.commons.auth.LoginActivity; +import fr.free.nrw.commons.category.CategoryContentProvider; +import fr.free.nrw.commons.contributions.ContributionsContentProvider; import fr.free.nrw.commons.contributions.ContributionsSyncAdapter; +import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.modifications.ModificationsSyncAdapter; +import fr.free.nrw.commons.settings.SettingsFragment; @Singleton @Component(modules = { @@ -21,7 +28,7 @@ import fr.free.nrw.commons.modifications.ModificationsSyncAdapter; ServiceBuilderModule.class, ContentProviderBuilderModule.class }) -public interface CommonsApplicationComponent extends AndroidInjector { +public interface CommonsApplicationComponent extends AndroidInjector { void inject(CommonsApplication application); void inject(ContributionsSyncAdapter syncAdapter); @@ -30,6 +37,13 @@ public interface CommonsApplicationComponent extends AndroidInjector supportFragmentInjector; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + inject(); + super.onCreate(savedInstanceState); + } + + @Override + public AndroidInjector supportFragmentInjector() { + return supportFragmentInjector; + } + + private void inject() { + ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getApplicationContext()); + + AndroidInjector activityInjector = injection.activityInjector(); + + if (activityInjector == null) { + throw new NullPointerException("ApplicationlessInjection.activityInjector() returned null"); + } + + activityInjector.inject(this); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerBroadcastReceiver.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerBroadcastReceiver.java new file mode 100644 index 000000000..3c4cb9914 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerBroadcastReceiver.java @@ -0,0 +1,31 @@ +package fr.free.nrw.commons.di; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import dagger.android.AndroidInjector; + +public abstract class CommonsDaggerBroadcastReceiver extends BroadcastReceiver { + + public CommonsDaggerBroadcastReceiver() { + super(); + } + + @Override + public void onReceive(Context context, Intent intent) { + inject(context); + } + + private void inject(Context context) { + ApplicationlessInjection injection = ApplicationlessInjection.getInstance(context.getApplicationContext()); + + AndroidInjector serviceInjector = injection.broadcastReceiverInjector(); + + if (serviceInjector == null) { + throw new NullPointerException("ApplicationlessInjection.broadcastReceiverInjector() returned null"); + } + serviceInjector.inject(this); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerContentProvider.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerContentProvider.java new file mode 100644 index 000000000..38506c4ca --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerContentProvider.java @@ -0,0 +1,32 @@ +package fr.free.nrw.commons.di; + +import android.content.ContentProvider; + +import dagger.android.AndroidInjector; + + +public abstract class CommonsDaggerContentProvider extends ContentProvider { + + public CommonsDaggerContentProvider() { + super(); + } + + @Override + public boolean onCreate() { + inject(); + return true; + } + + private void inject() { + ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getContext()); + + AndroidInjector serviceInjector = injection.contentProviderInjector(); + + if (serviceInjector == null) { + throw new NullPointerException("ApplicationlessInjection.contentProviderInjector() returned null"); + } + + serviceInjector.inject(this); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerIntentService.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerIntentService.java new file mode 100644 index 000000000..995c517a1 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerIntentService.java @@ -0,0 +1,32 @@ +package fr.free.nrw.commons.di; + +import android.app.IntentService; +import android.app.Service; + +import dagger.android.AndroidInjector; + +public abstract class CommonsDaggerIntentService extends IntentService { + + public CommonsDaggerIntentService(String name) { + super(name); + } + + @Override + public void onCreate() { + inject(); + super.onCreate(); + } + + private void inject() { + ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getApplicationContext()); + + AndroidInjector serviceInjector = injection.serviceInjector(); + + if (serviceInjector == null) { + throw new NullPointerException("ApplicationlessInjection.serviceInjector() returned null"); + } + + serviceInjector.inject(this); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerService.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerService.java new file mode 100644 index 000000000..dc6c10b9f --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerService.java @@ -0,0 +1,31 @@ +package fr.free.nrw.commons.di; + +import android.app.Service; + +import dagger.android.AndroidInjector; + +public abstract class CommonsDaggerService extends Service { + + public CommonsDaggerService() { + super(); + } + + @Override + public void onCreate() { + inject(); + super.onCreate(); + } + + private void inject() { + ApplicationlessInjection injection = ApplicationlessInjection.getInstance(getApplicationContext()); + + AndroidInjector serviceInjector = injection.serviceInjector(); + + if (serviceInjector == null) { + throw new NullPointerException("ApplicationlessInjection.serviceInjector() returned null"); + } + + serviceInjector.inject(this); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerSupportFragment.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerSupportFragment.java new file mode 100644 index 000000000..8c33e7a98 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsDaggerSupportFragment.java @@ -0,0 +1,65 @@ +package fr.free.nrw.commons.di; + +import android.app.Activity; +import android.content.Context; +import android.support.v4.app.Fragment; + +import javax.inject.Inject; + +import dagger.android.AndroidInjector; +import dagger.android.DispatchingAndroidInjector; +import dagger.android.support.HasSupportFragmentInjector; + +public abstract class CommonsDaggerSupportFragment extends Fragment implements HasSupportFragmentInjector { + + @Inject + DispatchingAndroidInjector childFragmentInjector; + + @Override + public void onAttach(Context context) { + inject(); + super.onAttach(context); + } + + @Override + public AndroidInjector supportFragmentInjector() { + return childFragmentInjector; + } + + + public void inject() { + HasSupportFragmentInjector hasSupportFragmentInjector = findHasFragmentInjector(); + + AndroidInjector fragmentInjector = hasSupportFragmentInjector.supportFragmentInjector(); + + if (fragmentInjector == null) { + throw new NullPointerException(String.format("%s.supportFragmentInjector() returned null", hasSupportFragmentInjector.getClass().getCanonicalName())); + } + + fragmentInjector.inject(this); + } + + private HasSupportFragmentInjector findHasFragmentInjector() { + Fragment parentFragment = this; + + while ((parentFragment = parentFragment.getParentFragment()) != null) { + if (parentFragment instanceof HasSupportFragmentInjector) { + return (HasSupportFragmentInjector) parentFragment; + } + } + + Activity activity = getActivity(); + + if (activity instanceof HasSupportFragmentInjector) { + return (HasSupportFragmentInjector) activity; + } + + ApplicationlessInjection injection = ApplicationlessInjection.getInstance(activity.getApplicationContext()); + if (injection != null) { + return injection; + } + + throw new IllegalArgumentException(String.format("No injector was found for %s", getClass().getCanonicalName())); + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 75e366767..60577ead7 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -24,7 +24,6 @@ import java.util.Locale; import javax.inject.Inject; import javax.inject.Provider; -import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.License; import fr.free.nrw.commons.LicenseList; import fr.free.nrw.commons.Media; @@ -32,12 +31,12 @@ import fr.free.nrw.commons.MediaDataExtractor; import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.PageTitle; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.ui.widget.CompatTextView; import timber.log.Timber; -public class MediaDetailFragment extends DaggerFragment { +public class MediaDetailFragment extends CommonsDaggerSupportFragment { private boolean editable; private MediaDetailPagerFragment.MediaDetailProvider detailProvider; diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index 5d6e66faf..d70b515bb 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -28,12 +28,12 @@ import android.view.ViewGroup; import javax.inject.Inject; import javax.inject.Named; -import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.Media; import fr.free.nrw.commons.R; import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.contributions.ContributionsActivity; +import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.mwapi.MediaWikiApi; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; @@ -41,7 +41,7 @@ import static android.content.Context.DOWNLOAD_SERVICE; import static android.content.Intent.ACTION_VIEW; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -public class MediaDetailPagerFragment extends DaggerFragment implements ViewPager.OnPageChangeListener { +public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment implements ViewPager.OnPageChangeListener { @Inject MediaWikiApi mwApi; @Inject SessionManager sessionManager; diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java index 3f2c01930..c7b92a3ec 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java @@ -1,6 +1,5 @@ package fr.free.nrw.commons.modifications; -import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; @@ -12,13 +11,13 @@ import android.text.TextUtils; import javax.inject.Inject; -import dagger.android.AndroidInjection; import fr.free.nrw.commons.data.DBOpenHelper; +import fr.free.nrw.commons.di.CommonsDaggerContentProvider; import timber.log.Timber; import static fr.free.nrw.commons.modifications.ModifierSequenceDao.Table.TABLE_NAME; -public class ModificationsContentProvider extends ContentProvider { +public class ModificationsContentProvider extends CommonsDaggerContentProvider { private static final int MODIFICATIONS = 1; private static final int MODIFICATIONS_ID = 2; @@ -40,12 +39,6 @@ public class ModificationsContentProvider extends ContentProvider { @Inject DBOpenHelper dbOpenHelper; - @Override - public boolean onCreate() { - AndroidInjection.inject(this); - return true; - } - @Override public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsSyncAdapter.java b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsSyncAdapter.java index f81c273d2..85bfedcfa 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsSyncAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsSyncAdapter.java @@ -20,6 +20,7 @@ import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.contributions.ContributionDao; import fr.free.nrw.commons.contributions.ContributionsContentProvider; +import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.mwapi.MediaWikiApi; import timber.log.Timber; @@ -36,7 +37,11 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter { @Override public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) { // This code is fraught with possibilities of race conditions, but lalalalala I can't hear you! - ((CommonsApplication)getContext().getApplicationContext()).injector().inject(this); + ApplicationlessInjection + .getInstance(getContext() + .getApplicationContext()) + .getCommonsApplicationComponent() + .inject(this); Cursor allModifications; try { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java index 81bc496f2..3cfb4840f 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java @@ -1,7 +1,9 @@ package fr.free.nrw.commons.nearby; +import android.content.Context; import android.net.Uri; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -16,13 +18,14 @@ import java.lang.reflect.Type; import java.util.Collections; import java.util.List; +import dagger.android.support.AndroidSupportInjection; import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.utils.UriDeserializer; import timber.log.Timber; -public class NearbyListFragment extends DaggerFragment { +public class NearbyListFragment extends Fragment { private static final Type LIST_TYPE = new TypeToken>() { }.getType(); private static final Type CUR_LAT_LNG_TYPE = new TypeToken() { @@ -40,6 +43,12 @@ public class NearbyListFragment extends DaggerFragment { setRetainInstance(true); } + @Override + public void onAttach(Context context) { + AndroidSupportInjection.inject(this); + super.onAttach(context); + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java index ca0ae0a89..7a907a1e4 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java @@ -1,11 +1,14 @@ package fr.free.nrw.commons.nearby; +import android.content.Context; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import butterknife.ButterKnife; +import dagger.android.support.AndroidSupportInjection; import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; import timber.log.Timber; @@ -13,11 +16,17 @@ import timber.log.Timber; /** * Tells user that Nearby Places cannot be displayed if location permissions are denied */ -public class NoPermissionsFragment extends DaggerFragment { +public class NoPermissionsFragment extends Fragment { public NoPermissionsFragment() { } + @Override + public void onAttach(Context context) { + AndroidSupportInjection.inject(this); + super.onAttach(context); + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index 33e42e4be..2a017c854 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -30,6 +30,7 @@ import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.utils.FileUtils; public class SettingsFragment extends PreferenceFragment { @@ -40,8 +41,11 @@ public class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); super.onCreate(savedInstanceState); + ApplicationlessInjection + .getInstance(getActivity().getApplicationContext()) + .getCommonsApplicationComponent() + .inject(this); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); diff --git a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java index f08496914..8ef8e84a4 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java @@ -4,10 +4,10 @@ import android.content.Intent; import android.os.Bundle; import android.preference.PreferenceManager; -import dagger.android.support.DaggerAppCompatActivity; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.di.CommonsDaggerAppCompatActivity; -public abstract class BaseActivity extends DaggerAppCompatActivity { +public abstract class BaseActivity extends CommonsDaggerAppCompatActivity { boolean currentTheme; @Override diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java index d20d8c1eb..0b6e527e5 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java @@ -5,6 +5,7 @@ import android.graphics.Point; import android.net.Uri; import android.os.Bundle; import android.support.graphics.drawable.VectorDrawableCompat; +import android.support.v4.app.Fragment; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -27,12 +28,12 @@ import android.widget.TextView; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; -import dagger.android.support.DaggerFragment; +import dagger.android.support.AndroidSupportInjection; import fr.free.nrw.commons.R; import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.media.MediaDetailPagerFragment; -public class MultipleUploadListFragment extends DaggerFragment { +public class MultipleUploadListFragment extends Fragment { public interface OnMultipleUploadInitiatedHandler { void OnMultipleUploadInitiated(); @@ -56,6 +57,12 @@ public class MultipleUploadListFragment extends DaggerFragment { private RelativeLayout overlay; } + @Override + public void onAttach(Context context) { + AndroidSupportInjection.inject(this); + super.onAttach(context); + } + private class PhotoDisplayAdapter extends BaseAdapter { @Override diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java index 259f38c36..be2401b5c 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java @@ -36,16 +36,16 @@ import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnItemSelected; import butterknife.OnTouch; -import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.settings.Prefs; import timber.log.Timber; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; -public class SingleUploadFragment extends DaggerFragment { +public class SingleUploadFragment extends CommonsDaggerSupportFragment { @BindView(R.id.titleEdit) EditText titleEdit; @BindView(R.id.descEdit) EditText descEdit; diff --git a/app/src/main/res/values-sr-el/error.xml b/app/src/main/res/values-sr-el/error.xml deleted file mode 100644 index 80d668c8b..000000000 --- a/app/src/main/res/values-sr-el/error.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - Ostava se srušila - Ups! Nešto je pošlo naopako. - Recite nam šta ste radili pa to saznanje podelite s nama, putem e-pošte. Time ćete nam pomoći da rešimo problem! - Hvala vam! - diff --git a/app/src/main/res/values-sr-el/strings.xml b/app/src/main/res/values-sr-el/strings.xml deleted file mode 100644 index 3cf62f69c..000000000 --- a/app/src/main/res/values-sr-el/strings.xml +++ /dev/null @@ -1,208 +0,0 @@ - - - Ostava - Podešavanja - Korisničko ime - Lozinka - Prijavi me - Otvori nalog - Prijavljivanje - Sačekajte… - Uspešno ste prijavljeni. - Prijavljivanje nije uspelo. - Datoteka nije pronađena. Pokušajte sa drugom datotekom. - Provera identiteta nije uspela. - Otpremanje je započeto. - Datoteka „%1$s“ je otpremljena. - Tapnite da biste videli otpremanje - Počinjem sa otpremanjem datoteke „%1$s“ - Otpremanje datoteke „%1$s“ - Završavam sa otpremanjem datoteke „%1$s“ - Ne mogu da otpremim „%1$s“ - Tapnite da biste videli - - %d datoteka se otprema - %d datoteke se otpremaju - - Moja skorašnja otpremanja - Na čekanju - Nije uspelo - %1$d%% otpremljeno - Otpremam - Iz galerije - Fotografiši - U blizini - Moja otpremanja - Deli - Otvori u pregledaču - Naslov - Opis - Ne mogu da vas prijavim – mreža ne radi - Ne mogu da vas prijavim – proverite svoje korisničko ime - Ne mogu da vas prijavim – proverite svoju lozinku - Previše neuspešnih pokušaja. Probajte ponovo za nekoliko minuta. - Nažalost, korisnik je blokiran na Ostavi - Morate uneti svoj dvofaktorski kod za autentifikaciju. - Prijava nije uspela - Otpremi - Dajte ime ovom kompletu - Izmene - Otpremi - Pretraži kategorije - Sačuvaj - Osveži - GPS je onemogućen na Vašem uređaju. Želite li ga omogućiti? - Omogući GPS - Još uvek nema otpremanja - - \@string/contributions_subtitle_zero - %d otpremanje - %d otpremanja - - - Započni %d otpremanje - Započni %d otpremanja - - - %d otpremanje - %d otpremanja - - Nema kategorija koje odgovaraju %1$s - Dodajte kategorije na slike da biste olakšali korisnicima njihovo pronalaženje na Ostavi.\n\nDa biste dodali kategoriju, počnite sa pisanjem njenog imena. - Kategorije - Postavke - Otvori nalog - O aplikaciji - Softver otvorenog koda dostupan pod licencom <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache ver. 2</a> Vikimedijina Ostava i njen logo su zaštitni znaci Vikimedijine Fondacije i koriste se sa dozvolom Vikimedijine Fondacine. Mi ne odobravamo ili podržavmo Vikimedijinu Fondaciju.\n\nAplikacija za Vikimedijinu ostavu je aplikacija otvorenog koda koja je napravljena i koja se održava pomoću grantova i volontera Vikimedijine zajednice. Zadužbina Vikimedija nije uključena u stvaranje, razvoj ili održavanje aplikacije. - <a href=\"https://github.com/commons-app/apps-android-commons\">Izvorni kôd</a> i <a href=\"https://commons-app.github.io/\">veb-sajt</a> na GitHub-u. Napravite novi <a href=\"https://github.com/commons-app/apps-android-commons/issues\">zahtev na GitHub-u</a> da biste prijavili greške ili dali predloge. - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Politika privatnosti</a> - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Zasluge</a> - O aplikaciji - Pošaljite povratne informacije (putem e-pošte) - Nije instaliran imejl klijent - Nedavno korišćene kategorije - Čekam na prvu sinhronizaciju… - Još niste otpremili nijednu fotografiju. - Pokušaj ponovo - Otkaži - Slika će se voditi pod licencom %1$s - Slanjem ove slike, ja tvrdim da je u pitanju moj rad, da ne sadrži materijal ili selfije zaštićene autorskim pravima, te da je na ostale načine u skladu sa <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">smernicama Vikimedijine ostave</a>. - Preuzmi - Licenca - Koristi prethodan naslov/opis - Automatski detektuj trenutnu lokaciju - Primi trenutnu lokaciju da bi predložili kategoriju ako slika nije geografski označena - Noćni režim - Koristiti tamnu temu - Autorstvo-Deliti pod istim uslovima 4.0 - Autorstvo 4.0 - Autorstvo-Deliti pod istim uslovimau 3.0 - Autorstvo 3.0 - CC0 - CC BY-SA 3.0 - CC BY-SA 3.0 (Austrija) - CC BY-SA 3.0 (Nemačka) - CC BY-SA 3.0 (Estonija) - CC BY-SA 3.0 (Španija) - CC BY-SA 3.0 (Hrvatska) - CC BY-SA 3.0 (Luksemburg) - CC BY-SA 3.0 (Holandija) - CC BY-SA 3.0 (Norveška) - CC BY-SA 3.0 (Poljska) - CC BY-SA 3.0 (Rumunija) - CC BY 3.0 - CC BY-SA 4.0 - CC BY 4.0 - CC Nula - Vikimedijina Ostava sadrži većinu slika koja se koristi na Vikipediji. - Vaše slike pomažu u obrazovanju ljudi širom sveta. - Molimo Vas da postavite slike koje ste preuzeli ili kreirali u potpunosti sami: - - Prirodne objekte (cveće, životinje, planine)\n- Korisne objekte (bicikle, železničke stanice)\n- Poznate ljude (vaš gradonačelnik, Olimpijce koje ste sreli) - Molimo NE otpremajte: - - Selfije i slike tvojih prijatelja\n- Slike koje ste preuzeli sa interneta\n- Skrinšotove iz sopstvenih aplikacija - Primer otpremanja: - — Naslov: Sidnejska opera\n— Opis: Sidnejska opera, pogled preko zaliva\n— Kategorije: Sidnejska opera sa zapada, pogledi na Sidnejksu operu iz daljine - Delite svoje slike. Oživite članke na Vikipediji! - Slike na Vikipediji dolaze iz Ostave. - Sa vašim slikama pomažete u obrazovanju ljudi širom sveta. - Izbegavajte materijale koje ste našli na internetu, kao i slike plakata, korica knjiga itd. - Jeste li razumeli? - Jesam! - Kategorije - Učitavam… - Ništa nije izabrano - Nema opisa - Nepoznata licenca - Osveži - Potrebna dozvola: Provera spoljašnje memorije. Aplikacija bez ovoga ne može da funkcioniše. - Neophodna dozvola: Pisanje spoljašnjeg skladišta. Aplikacija ne može da funkcioniše bez ovoga. - Opciona dozvola: Preuzmi trenutnu lokaciju za predloge kategorija - U redu - Mesta u blizini - Nisu pronađena obližnja mesta - Upozorenje - Ova datoteka je već dostupna na Ostavi. Da li ste sigurni da želite da nastavite? - Da - Ne - Naslov - Naslov medija - Opis - Opis datoteke ide ovde. Može da bude poprilično dug i prikazivaće se u više redova. Nadamo se da će izgledati lepo. - Datum otpremanja - Licenca - Koordinate - Ništa nije uneto - Postani Beta Tester - Priključite se na naš beta kanal na Gugl pleju i pristupajte novim informacijama i popravkama bagova - Koristi Vikipodatke - (Upozorenje: onemogućavanjem ovoga može se izazvati velika potrošnja mobilnih podataka) - 2FA kod - Moj limit za skorašnja otpremanja - Maksimalni limit - Nije moguće prikazati više od 500 - Postavi limit za skorašnja otpremanja - Dvofaktorska autentifikacija trenutno nije podržana. - Zaista želite da se odjavite? - Logo Ostave - Pozadinska slika - Medijska slika neuspešna - Slika nije pronađena - Otpremi sliku - Planina Zao - Lame - Dugin most - Tulipan - Bez selfija - Vlasnička slika - Dobrodošlica Vikipediji - Dobrodošlica za autorska prava - Sidnejska opera - Otkaži - Otvori - Zatvori - Početna - Otpremanje - U blizini - O nama - Podešavanja - Povratne informacije - Odjavi me - Tutorijal - Obaveštenja - Obližnja mesta ne mogu da se prikazuju bez dozvola za lokaciju - opis nije pronađen - Stranica datoteke na Ostavi - Stavka na Vikipodacima - Greška pri keširanju slika - Jedinstven opisni naslov za datoteku, koji će biti ime datoteke. Možete da koristite obični jezik sa razmacima. Ne treba unositi ekstenziju datoteke - Molimo da opišete datoteku koliko je to moguće: Gde je napravljena? Šta prikazuje? Šta je kontekst? Opišite objekte i/ili osobe. Otkrijte informacije koje se ne mogu lako pogoditi, na primer doba dana ako je u pitanju pejzaž. Ako datoteka prikazuje nešto neobično, molimo da objasnite šta je to čini neobičnom. - Davanje dozvole - Upotreba spoljašnjeg skladišta - Spremanje slika napravljenih kamerom aplikacije na Vašem uređaju - Pošalji dnevničku datoteku - Pošalji dnevničku datoteku developerima preko imejla - Prijavite se na svoj nalog - Lokacija nije promenjena. - Lokacija nije dostupna. - Potrebna je dozvola za prikazivanje liste lokacija u blizini -