mirror of
https://github.com/MinimalBible/MinimalBible
synced 2024-11-04 15:18:22 -05:00
Add a language spinner
It doesn't do much yet...
This commit is contained in:
parent
23bd5136b5
commit
88a40cbfbb
@ -40,9 +40,12 @@ import static org.mockito.Mockito.when;
|
|||||||
public class BookDownloadManagerTest extends MBTestCase implements Injector {
|
public class BookDownloadManagerTest extends MBTestCase implements Injector {
|
||||||
|
|
||||||
ObjectGraph mObjectGraph;
|
ObjectGraph mObjectGraph;
|
||||||
@Inject BookDownloadManager bookDownloadManager;
|
@Inject
|
||||||
@Inject RefreshManager refreshManager;
|
BookDownloadManager bookDownloadManager;
|
||||||
@Inject Books installedBooks;
|
@Inject
|
||||||
|
RefreshManager refreshManager;
|
||||||
|
@Inject
|
||||||
|
Books installedBooks;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inject(Object o) {
|
public void inject(Object o) {
|
||||||
@ -56,7 +59,7 @@ public class BookDownloadManagerTest extends MBTestCase implements Injector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Observable<Book> installableBooks() {
|
Observable<Book> installableBooks() {
|
||||||
return refreshManager.getAvailableModulesFlat()
|
return refreshManager.getFlatModules()
|
||||||
.filter(new Func1<Book, Boolean>() {
|
.filter(new Func1<Book, Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean call(Book book) {
|
public Boolean call(Book book) {
|
||||||
@ -121,6 +124,7 @@ public class BookDownloadManagerTest extends MBTestCase implements Injector {
|
|||||||
Injector i;
|
Injector i;
|
||||||
ConnectivityManager manager;
|
ConnectivityManager manager;
|
||||||
DownloadPrefs prefs;
|
DownloadPrefs prefs;
|
||||||
|
|
||||||
BookDownloadManagerTestModules(Injector i) {
|
BookDownloadManagerTestModules(Injector i) {
|
||||||
this.i = i;
|
this.i = i;
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ public class RefreshManagerTest extends MBTestCase implements Injector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testGetAvailableModulesFlattened() throws Exception {
|
public void testGetAvailableModulesFlattened() throws Exception {
|
||||||
rM.getAvailableModulesFlat()
|
rM.getFlatModules()
|
||||||
.toBlocking()
|
.toBlocking()
|
||||||
.forEach(new Action1<Book>() {
|
.forEach(new Action1<Book>() {
|
||||||
@Override
|
@Override
|
||||||
@ -134,15 +134,15 @@ public class RefreshManagerTest extends MBTestCase implements Injector {
|
|||||||
long fourteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1209600;
|
long fourteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1209600;
|
||||||
long sixteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1382400;
|
long sixteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1382400;
|
||||||
|
|
||||||
assertFalse(rM.doReload(true, fourteenDaysAgo, false));
|
assertFalse(rM.doReload(true, fourteenDaysAgo, ConnectivityManager.TYPE_DUMMY));
|
||||||
assertFalse(rM.doReload(true, fourteenDaysAgo, true));
|
assertFalse(rM.doReload(true, fourteenDaysAgo, ConnectivityManager.TYPE_WIFI));
|
||||||
assertFalse(rM.doReload(true, sixteenDaysAgo, false));
|
assertFalse(rM.doReload(true, sixteenDaysAgo, ConnectivityManager.TYPE_DUMMY));
|
||||||
assertTrue(rM.doReload(true, sixteenDaysAgo, true));
|
assertTrue(rM.doReload(true, sixteenDaysAgo, ConnectivityManager.TYPE_WIFI));
|
||||||
|
|
||||||
assertFalse(rM.doReload(false, fourteenDaysAgo, true));
|
assertFalse(rM.doReload(false, fourteenDaysAgo, ConnectivityManager.TYPE_WIFI));
|
||||||
assertFalse(rM.doReload(false, fourteenDaysAgo, false));
|
assertFalse(rM.doReload(false, fourteenDaysAgo, ConnectivityManager.TYPE_DUMMY));
|
||||||
assertFalse(rM.doReload(false, sixteenDaysAgo, true));
|
assertFalse(rM.doReload(false, sixteenDaysAgo, ConnectivityManager.TYPE_WIFI));
|
||||||
assertFalse(rM.doReload(false, sixteenDaysAgo, false));
|
assertFalse(rM.doReload(false, sixteenDaysAgo, ConnectivityManager.TYPE_DUMMY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module(injects = {RefreshManagerTest.class, RefreshManager.class})
|
@Module(injects = {RefreshManagerTest.class, RefreshManager.class})
|
||||||
@ -151,6 +151,7 @@ public class RefreshManagerTest extends MBTestCase implements Injector {
|
|||||||
Collection<Installer> installers;
|
Collection<Installer> installers;
|
||||||
ConnectivityManager manager;
|
ConnectivityManager manager;
|
||||||
DownloadPrefs prefs;
|
DownloadPrefs prefs;
|
||||||
|
|
||||||
RMTModules(Collection<Installer> installers) {
|
RMTModules(Collection<Installer> installers) {
|
||||||
this.installers = installers;
|
this.installers = installers;
|
||||||
|
|
||||||
|
@ -12,15 +12,29 @@ import com.readystatesoftware.systembartint.SystemBarTintManager;
|
|||||||
*/
|
*/
|
||||||
public class BaseFragment extends Fragment {
|
public class BaseFragment extends Fragment {
|
||||||
|
|
||||||
|
protected static SystemBarTintManager.SystemBarConfig getConfig(Activity context) {
|
||||||
|
return new SystemBarTintManager(context).getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the offset we need to display properly if the System bar is translucent
|
* Calculate the offset we need to display properly if the System bar is translucent
|
||||||
* @param context The {@link android.app.Activity} we are displaying in
|
* @param context The {@link android.app.Activity} we are displaying in
|
||||||
* @param view The {@link android.view.View} we need to calculate the offset for.
|
* @param view The {@link android.view.View} we need to calculate the offset for.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
protected static void setInsets(Activity context, View view) {
|
protected static void setInsets(Activity context, View view) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
|
||||||
SystemBarTintManager tintManager = new SystemBarTintManager(context);
|
SystemBarTintManager.SystemBarConfig config = getConfig(context);
|
||||||
SystemBarTintManager.SystemBarConfig config = tintManager.getConfig();
|
|
||||||
view.setPadding(0, config.getPixelInsetTop(true), config.getPixelInsetRight(), config.getPixelInsetBottom());
|
view.setPadding(0, config.getPixelInsetTop(true), config.getPixelInsetRight(), config.getPixelInsetBottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void setInsetsSpinner(Activity context, View view) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
|
||||||
|
SystemBarTintManager.SystemBarConfig config = getConfig(context);
|
||||||
|
int marginTopBottom = config.getPixelInsetBottom() / 3;
|
||||||
|
view.setPadding(0, config.getPixelInsetTop(true) + marginTopBottom,
|
||||||
|
config.getPixelInsetRight(),
|
||||||
|
marginTopBottom);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,16 @@ import android.os.Bundle;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.SpinnerAdapter;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.bspeice.minimalbible.Injector;
|
import org.bspeice.minimalbible.Injector;
|
||||||
import org.bspeice.minimalbible.R;
|
import org.bspeice.minimalbible.R;
|
||||||
import org.bspeice.minimalbible.activity.BaseFragment;
|
import org.bspeice.minimalbible.activity.BaseFragment;
|
||||||
|
import org.bspeice.minimalbible.activity.downloader.manager.LocaleManager;
|
||||||
import org.bspeice.minimalbible.activity.downloader.manager.RefreshManager;
|
import org.bspeice.minimalbible.activity.downloader.manager.RefreshManager;
|
||||||
import org.crosswire.jsword.book.Book;
|
import org.crosswire.jsword.book.Book;
|
||||||
import org.crosswire.jsword.book.BookCategory;
|
import org.crosswire.jsword.book.BookCategory;
|
||||||
@ -36,18 +40,18 @@ import rx.functions.Func2;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class BookListFragment extends BaseFragment {
|
public class BookListFragment extends BaseFragment {
|
||||||
/**
|
|
||||||
* The fragment argument representing the section number for this fragment.
|
|
||||||
* Not a candidate for Dart (yet) because I would have to write a Parcelable around it.
|
|
||||||
*/
|
|
||||||
protected static final String ARG_BOOK_CATEGORY = "book_category";
|
protected static final String ARG_BOOK_CATEGORY = "book_category";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected DownloadPrefs downloadPrefs;
|
protected DownloadPrefs downloadPrefs;
|
||||||
protected ProgressDialog refreshDialog;
|
protected ProgressDialog refreshDialog;
|
||||||
|
@Inject RefreshManager refreshManager;
|
||||||
|
@Inject
|
||||||
|
LocaleManager localeManager;
|
||||||
@InjectView(R.id.lst_download_available)
|
@InjectView(R.id.lst_download_available)
|
||||||
ListView downloadsAvailable;
|
ListView downloadsAvailable;
|
||||||
@Inject RefreshManager refreshManager;
|
@InjectView(R.id.spn_available_languages)
|
||||||
|
Spinner availableLanguages;
|
||||||
private LayoutInflater inflater;
|
private LayoutInflater inflater;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,7 +125,7 @@ public class BookListFragment extends BaseFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Listen for the books!
|
// Listen for the books!
|
||||||
refreshManager.getAvailableModulesFlat()
|
refreshManager.getFlatModules()
|
||||||
.filter(new Func1<Book, Boolean>() {
|
.filter(new Func1<Book, Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean call(Book book) {
|
public Boolean call(Book book) {
|
||||||
@ -143,12 +147,13 @@ public class BookListFragment extends BaseFragment {
|
|||||||
public void call(List<Book> books) {
|
public void call(List<Book> books) {
|
||||||
downloadsAvailable.setAdapter(
|
downloadsAvailable.setAdapter(
|
||||||
new BookListAdapter(inflater, books, (DownloadActivity)getActivity()));
|
new BookListAdapter(inflater, books, (DownloadActivity)getActivity()));
|
||||||
|
availableLanguages.setAdapter(getLocaleSpinner());
|
||||||
if (BookListFragment.this.getActivity() != null) {
|
if (BookListFragment.this.getActivity() != null) {
|
||||||
// On a screen rotate, getActivity() will be null. But, the activity
|
// On a screen rotate, getActivity() will be null. But, the activity
|
||||||
// will already have been set up correctly, so we don't need to worry
|
// will already have been set up correctly, so we don't need to worry
|
||||||
// about it.
|
// about it.
|
||||||
// If not null, we need to set it up now.
|
// If not null, we need to set it up now.
|
||||||
setInsets(BookListFragment.this.getActivity(), downloadsAvailable);
|
setInsetsSpinner(BookListFragment.this.getActivity(), availableLanguages);
|
||||||
}
|
}
|
||||||
if (refreshDialog != null) {
|
if (refreshDialog != null) {
|
||||||
refreshDialog.cancel();
|
refreshDialog.cancel();
|
||||||
@ -157,35 +162,45 @@ public class BookListFragment extends BaseFragment {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DownloadDialogListener implements
|
@SuppressWarnings("ConstantConditions")
|
||||||
DialogInterface.OnClickListener {
|
// getAvailableLanguagesList() will not return null
|
||||||
@Override
|
SpinnerAdapter getLocaleSpinner() {
|
||||||
|
ArrayAdapter<Object> adapter = new ArrayAdapter<Object>(this.getActivity(),
|
||||||
|
android.R.layout.simple_spinner_item,
|
||||||
|
localeManager.getAvailableLanguagesList().toArray());
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DownloadDialogListener implements
|
||||||
|
DialogInterface.OnClickListener {
|
||||||
|
@Override
|
||||||
public void onClick(@NotNull DialogInterface dialog, int which) {
|
public void onClick(@NotNull DialogInterface dialog, int which) {
|
||||||
downloadPrefs.hasShownDownloadDialog(true);
|
downloadPrefs.hasShownDownloadDialog(true);
|
||||||
|
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case DialogInterface.BUTTON_POSITIVE:
|
case DialogInterface.BUTTON_POSITIVE:
|
||||||
// Clicked ready to continue - allow downloading in the future
|
// Clicked ready to continue - allow downloading in the future
|
||||||
downloadPrefs.hasEnabledDownload(true);
|
downloadPrefs.hasEnabledDownload(true);
|
||||||
|
|
||||||
// And warn them that it has been enabled in the future.
|
// And warn them that it has been enabled in the future.
|
||||||
Toast.makeText(getActivity(),
|
Toast.makeText(getActivity(),
|
||||||
"Downloading now enabled. Disable in settings.",
|
"Downloading now enabled. Disable in settings.",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
refreshModules();
|
refreshModules();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case DialogInterface.BUTTON_NEGATIVE:
|
// case DialogInterface.BUTTON_NEGATIVE:
|
||||||
default:
|
default:
|
||||||
// Clicked to not download - Permanently disable downloading
|
// Clicked to not download - Permanently disable downloading
|
||||||
downloadPrefs.hasEnabledDownload(false);
|
downloadPrefs.hasEnabledDownload(false);
|
||||||
Toast.makeText(getActivity(),
|
Toast.makeText(getActivity(),
|
||||||
"Disabling downloading. Re-enable it in settings.",
|
"Disabling downloading. Re-enable it in settings.",
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
refreshModules();
|
refreshModules();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import org.bspeice.minimalbible.Injector;
|
|||||||
import org.bspeice.minimalbible.MinimalBibleModules;
|
import org.bspeice.minimalbible.MinimalBibleModules;
|
||||||
import org.bspeice.minimalbible.activity.downloader.manager.BookDownloadManager;
|
import org.bspeice.minimalbible.activity.downloader.manager.BookDownloadManager;
|
||||||
import org.bspeice.minimalbible.activity.downloader.manager.InstalledManager;
|
import org.bspeice.minimalbible.activity.downloader.manager.InstalledManager;
|
||||||
|
import org.bspeice.minimalbible.activity.downloader.manager.LocaleManager;
|
||||||
import org.bspeice.minimalbible.activity.downloader.manager.RefreshManager;
|
import org.bspeice.minimalbible.activity.downloader.manager.RefreshManager;
|
||||||
import org.crosswire.jsword.book.Book;
|
import org.crosswire.jsword.book.Book;
|
||||||
import org.crosswire.jsword.book.BookCategory;
|
import org.crosswire.jsword.book.BookCategory;
|
||||||
@ -112,4 +113,9 @@ public class DownloadActivityModules {
|
|||||||
return new RefreshManager(installers, prefs,
|
return new RefreshManager(installers, prefs,
|
||||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
|
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
LocaleManager provideLocaleManager(RefreshManager refreshManager) {
|
||||||
|
return new LocaleManager(refreshManager);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package org.bspeice.minimalbible.activity.downloader.manager
|
||||||
|
|
||||||
|
import org.crosswire.common.util.Language
|
||||||
|
|
||||||
|
class LocaleManager(val rM: RefreshManager) {
|
||||||
|
|
||||||
|
val currentLanguage = Language.DEFAULT_LANG.getName()
|
||||||
|
val languageModuleMap = rM.flatModules
|
||||||
|
.map { it.getLanguage() ?: Language(Language.UNKNOWN_LANG_CODE) }
|
||||||
|
.groupBy { it.getName() }
|
||||||
|
|
||||||
|
val availableLanguages = languageModuleMap.map { it.getKey() }
|
||||||
|
val availableLanguagesList = availableLanguages.toSortedList {(left, right) ->
|
||||||
|
// Prioritize our current language first
|
||||||
|
if (left == currentLanguage)
|
||||||
|
-1
|
||||||
|
else if (right == currentLanguage)
|
||||||
|
1
|
||||||
|
else
|
||||||
|
left.compareTo(right)
|
||||||
|
}.toBlocking().first()
|
||||||
|
}
|
@ -8,6 +8,7 @@ import rx.schedulers.Schedulers
|
|||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import org.bspeice.minimalbible.activity.downloader.DownloadPrefs
|
import org.bspeice.minimalbible.activity.downloader.DownloadPrefs
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
|
import org.crosswire.jsword.book.BookComparators
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by bspeice on 10/22/14.
|
* Created by bspeice on 10/22/14.
|
||||||
@ -21,19 +22,23 @@ class RefreshManager(val installers: Collection<Installer>,
|
|||||||
Observable.from(installers)
|
Observable.from(installers)
|
||||||
.map {
|
.map {
|
||||||
if (doReload()) {
|
if (doReload()) {
|
||||||
it.reloadBookList()
|
it.reloadBookList() // TODO: Handle InstallException
|
||||||
}
|
}
|
||||||
mapOf(Pair(it, it.getBooks()))
|
mapOf(Pair(it, it.getBooks()))
|
||||||
}
|
}
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.cache();
|
.cache();
|
||||||
|
|
||||||
val availableModulesFlat: Observable<Book>
|
val flatModules: Observable<Book> =
|
||||||
get() = availableModules
|
availableModules
|
||||||
// Map -> Lists
|
// Map -> Lists
|
||||||
.flatMap { Observable.from(it.values()) }
|
.flatMap { Observable.from(it.values()) }
|
||||||
// Lists -> Single list
|
// Lists -> Single list
|
||||||
.flatMap { Observable.from(it) };
|
.flatMap { Observable.from(it) }
|
||||||
|
|
||||||
|
val flatModulesSorted = flatModules.toSortedList {(book1, book2) ->
|
||||||
|
BookComparators.getInitialComparator().compare(book1, book2)
|
||||||
|
};
|
||||||
|
|
||||||
// Constructor - Split from the value creation because `subscribe` returns
|
// Constructor - Split from the value creation because `subscribe` returns
|
||||||
// the subscriber object, not the underlying value
|
// the subscriber object, not the underlying value
|
||||||
@ -43,8 +48,9 @@ class RefreshManager(val installers: Collection<Installer>,
|
|||||||
|
|
||||||
val fifteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1296000
|
val fifteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1296000
|
||||||
|
|
||||||
fun doReload(enabledDownload: Boolean, lastUpdated: Long, onWifi: Boolean): Boolean =
|
fun doReload(enabledDownload: Boolean, lastUpdated: Long,
|
||||||
if (!enabledDownload || !onWifi)
|
networkState: Int? = ConnectivityManager.TYPE_DUMMY): Boolean =
|
||||||
|
if (!enabledDownload || networkState == ConnectivityManager.TYPE_WIFI)
|
||||||
false
|
false
|
||||||
else if (lastUpdated < fifteenDaysAgo)
|
else if (lastUpdated < fifteenDaysAgo)
|
||||||
true
|
true
|
||||||
@ -53,12 +59,7 @@ class RefreshManager(val installers: Collection<Installer>,
|
|||||||
|
|
||||||
fun doReload(): Boolean = doReload(prefs.hasEnabledDownload(),
|
fun doReload(): Boolean = doReload(prefs.hasEnabledDownload(),
|
||||||
prefs.downloadRefreshedOn(),
|
prefs.downloadRefreshedOn(),
|
||||||
// TODO: Functional is awesome, but this might be a bit ridiculous
|
connManager?.getActiveNetworkInfo()?.getType())
|
||||||
(if (connManager?.getActiveNetworkInfo() != null)
|
|
||||||
connManager!!.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI
|
|
||||||
else
|
|
||||||
false)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun installerFromBook(b: Book): Observable<Installer> = Observable.just(
|
fun installerFromBook(b: Book): Observable<Installer> = Observable.just(
|
||||||
availableModules.filter {
|
availableModules.filter {
|
||||||
|
@ -4,12 +4,19 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="org.bspeice.minimalbible.DownloadActivity$PlaceholderFragment" >
|
tools:context="org.bspeice.minimalbible.DownloadActivity$PlaceholderFragment" >
|
||||||
|
|
||||||
<ListView
|
<Spinner
|
||||||
|
android:id="@+id/spn_available_languages"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/lst_download_available"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:clipToPadding="false" />
|
android:layout_alignParentTop="true" />
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/lst_download_available"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_below="@+id/spn_available_languages" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
Loading…
Reference in New Issue
Block a user