Skip to content

Commit 4194409

Browse files
authored
Fixes 4544 : Language selection: history (commons-app#4880)
* Xml changes * Content provider created * Database setup done * Database setup revised * Database setup revised * SettingsFragment finished * SettingsFragment finished * UploadMediaDetailFragment updated * UploadMediaDetailFragment updated * Java docs * Test fixed * Test added * Test added * Test updated * More tests added
1 parent 85bdcd5 commit 4194409

20 files changed

+1312
-9
lines changed

app/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ android {
259259
buildConfigField "String", "MODIFICATION_AUTHORITY", "\"fr.free.nrw.commons.modifications.contentprovider\""
260260
buildConfigField "String", "CATEGORY_AUTHORITY", "\"fr.free.nrw.commons.categories.contentprovider\""
261261
buildConfigField "String", "RECENT_SEARCH_AUTHORITY", "\"fr.free.nrw.commons.explore.recentsearches.contentprovider\""
262+
buildConfigField "String", "RECENT_LANGUAGE_AUTHORITY", "\"fr.free.nrw.commons.recentlanguages.contentprovider\""
262263
buildConfigField "String", "BOOKMARK_AUTHORITY", "\"fr.free.nrw.commons.bookmarks.contentprovider\""
263264
buildConfigField "String", "BOOKMARK_LOCATIONS_AUTHORITY", "\"fr.free.nrw.commons.bookmarks.locations.contentprovider\""
264265
buildConfigField "String", "BOOKMARK_ITEMS_AUTHORITY", "\"fr.free.nrw.commons.bookmarks.items.contentprovider\""
@@ -294,6 +295,7 @@ android {
294295
buildConfigField "String", "MODIFICATION_AUTHORITY", "\"fr.free.nrw.commons.beta.modifications.contentprovider\""
295296
buildConfigField "String", "CATEGORY_AUTHORITY", "\"fr.free.nrw.commons.beta.categories.contentprovider\""
296297
buildConfigField "String", "RECENT_SEARCH_AUTHORITY", "\"fr.free.nrw.commons.beta.explore.recentsearches.contentprovider\""
298+
buildConfigField "String", "RECENT_LANGUAGE_AUTHORITY", "\"fr.free.nrw.commons.beta.recentlanguages.contentprovider\""
297299
buildConfigField "String", "BOOKMARK_AUTHORITY", "\"fr.free.nrw.commons.beta.bookmarks.contentprovider\""
298300
buildConfigField "String", "BOOKMARK_LOCATIONS_AUTHORITY", "\"fr.free.nrw.commons.beta.bookmarks.locations.contentprovider\""
299301
buildConfigField "String", "BOOKMARK_ITEMS_AUTHORITY", "\"fr.free.nrw.commons.beta.bookmarks.items.contentprovider\""

app/src/main/AndroidManifest.xml

+7
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@
194194
android:label="@string/provider_searches"
195195
android:syncable="false" />
196196

197+
<provider
198+
android:name=".recentlanguages.RecentLanguagesContentProvider"
199+
android:authorities="${applicationId}.recentlanguages.contentprovider"
200+
android:exported="false"
201+
android:label="@string/provider_recent_languages"
202+
android:syncable="false" />
203+
197204
<provider
198205
android:name=".bookmarks.pictures.BookmarkPicturesContentProvider"
199206
android:authorities="${applicationId}.bookmarks.contentprovider"

app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
1212
import fr.free.nrw.commons.category.CategoryDao;
1313
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao;
14+
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao;
1415

1516
public class DBOpenHelper extends SQLiteOpenHelper {
1617

@@ -34,6 +35,7 @@ public void onCreate(SQLiteDatabase sqLiteDatabase) {
3435
BookmarkLocationsDao.Table.onCreate(sqLiteDatabase);
3536
BookmarkItemsDao.Table.onCreate(sqLiteDatabase);
3637
RecentSearchesDao.Table.onCreate(sqLiteDatabase);
38+
RecentLanguagesDao.Table.onCreate(sqLiteDatabase);
3739
}
3840

3941
@Override
@@ -43,6 +45,7 @@ public void onUpgrade(SQLiteDatabase sqLiteDatabase, int from, int to) {
4345
BookmarkLocationsDao.Table.onUpdate(sqLiteDatabase, from, to);
4446
BookmarkItemsDao.Table.onUpdate(sqLiteDatabase, from, to);
4547
RecentSearchesDao.Table.onUpdate(sqLiteDatabase, from, to);
48+
RecentLanguagesDao.Table.onUpdate(sqLiteDatabase, from, to);
4649
deleteTable(sqLiteDatabase,CONTRIBUTIONS_TABLE);
4750
}
4851

app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java

+13
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,19 @@ public ContentProviderClient provideBookmarkItemContentProviderClient(Context co
169169
return context.getContentResolver().acquireContentProviderClient(BuildConfig.BOOKMARK_ITEMS_AUTHORITY);
170170
}
171171

172+
/**
173+
* This method is used to provide instance of RecentLanguagesContentProvider
174+
* which provides content of recent used languages from database
175+
* @param context Context
176+
* @return returns RecentLanguagesContentProvider
177+
*/
178+
@Provides
179+
@Named("recent_languages")
180+
public ContentProviderClient provideRecentLanguagesContentProviderClient(final Context context) {
181+
return context.getContentResolver()
182+
.acquireContentProviderClient(BuildConfig.RECENT_LANGUAGE_AUTHORITY);
183+
}
184+
172185
/**
173186
* Provides a Json store instance(JsonKvStore) which keeps
174187
* the provided Gson in it's instance

app/src/main/java/fr/free/nrw/commons/di/ContentProviderBuilderModule.java

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
88
import fr.free.nrw.commons.category.CategoryContentProvider;
99
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider;
10+
import fr.free.nrw.commons.recentlanguages.RecentLanguagesContentProvider;
1011

1112
/**
1213
* This Class Represents the Module for dependency injection (using dagger)
@@ -31,4 +32,7 @@ public abstract class ContentProviderBuilderModule {
3132

3233
@ContributesAndroidInjector
3334
abstract BookmarkItemsContentProvider bindBookmarkItemContentProvider();
35+
36+
@ContributesAndroidInjector
37+
abstract RecentLanguagesContentProvider bindRecentLanguagesContentProvider();
3438
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package fr.free.nrw.commons.recentlanguages
2+
3+
data class Language(val languageName: String, val languageCode: String)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package fr.free.nrw.commons.recentlanguages
2+
3+
import android.content.Context
4+
import android.view.LayoutInflater
5+
import android.view.View
6+
import android.view.ViewGroup
7+
import android.widget.ArrayAdapter
8+
import fr.free.nrw.commons.R
9+
import fr.free.nrw.commons.utils.LangCodeUtils
10+
import kotlinx.android.synthetic.main.row_item_languages_spinner.view.*
11+
import org.apache.commons.lang3.StringUtils
12+
import java.util.HashMap
13+
14+
/**
15+
* Array adapter for recent languages
16+
*/
17+
class RecentLanguagesAdapter constructor(
18+
context: Context,
19+
var recentLanguages: List<Language>,
20+
private val selectedLanguages: HashMap<*, String>
21+
) : ArrayAdapter<String?>(context, R.layout.row_item_languages_spinner) {
22+
23+
/**
24+
* Selected language code in UploadMediaDetailAdapter
25+
* Used for marking selected ones
26+
*/
27+
var selectedLangCode = ""
28+
29+
override fun isEnabled(position: Int) = recentLanguages[position].languageCode.let {
30+
it.isNotEmpty() && !selectedLanguages.containsValue(it) && it != selectedLangCode
31+
}
32+
33+
override fun getCount() = recentLanguages.size
34+
35+
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
36+
val rowView: View = convertView
37+
?: LayoutInflater.from(context)
38+
.inflate(R.layout.row_item_languages_spinner, parent, false)
39+
val languageCode = recentLanguages[position].languageCode
40+
val languageName = recentLanguages[position].languageName
41+
rowView.tv_language.let {
42+
it.isEnabled = isEnabled(position)
43+
if (languageCode.isEmpty()) {
44+
it.text = StringUtils.capitalize(languageName)
45+
it.textAlignment = View.TEXT_ALIGNMENT_CENTER
46+
} else {
47+
it.text =
48+
"${StringUtils.capitalize(languageName)}" +
49+
" [${LangCodeUtils.fixLanguageCode(languageCode)}]"
50+
}
51+
}
52+
return rowView
53+
}
54+
55+
/**
56+
* Provides code of a language from recent languages for a specific position
57+
*/
58+
fun getLanguageCode(position: Int): String {
59+
return recentLanguages[position].languageCode
60+
}
61+
62+
/**
63+
* Provides name of a language from recent languages for a specific position
64+
*/
65+
fun getLanguageName(position: Int): String {
66+
return recentLanguages[position].languageName
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package fr.free.nrw.commons.recentlanguages;
2+
3+
import static fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.COLUMN_NAME;
4+
import static fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.TABLE_NAME;
5+
6+
import android.content.ContentValues;
7+
import android.database.Cursor;
8+
import android.database.sqlite.SQLiteDatabase;
9+
import android.database.sqlite.SQLiteQueryBuilder;
10+
import android.net.Uri;
11+
import android.text.TextUtils;
12+
import androidx.annotation.NonNull;
13+
import fr.free.nrw.commons.BuildConfig;
14+
import fr.free.nrw.commons.data.DBOpenHelper;
15+
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
16+
import javax.inject.Inject;
17+
import timber.log.Timber;
18+
19+
/**
20+
* Content provider of recently used languages
21+
*/
22+
public class RecentLanguagesContentProvider extends CommonsDaggerContentProvider {
23+
24+
private static final String BASE_PATH = "recent_languages";
25+
public static final Uri BASE_URI =
26+
Uri.parse("content://" + BuildConfig.RECENT_LANGUAGE_AUTHORITY + "/" + BASE_PATH);
27+
28+
29+
/**
30+
* Append language code to the base uri
31+
* @param languageCode Code of a language
32+
*/
33+
public static Uri uriForCode(final String languageCode) {
34+
return Uri.parse(BASE_URI + "/" + languageCode);
35+
}
36+
37+
@Inject
38+
DBOpenHelper dbOpenHelper;
39+
40+
@Override
41+
public String getType(@NonNull final Uri uri) {
42+
return null;
43+
}
44+
45+
/**
46+
* Queries the SQLite database for the recently used languages
47+
* @param uri : contains the uri for recently used languages
48+
* @param projection : contains the all fields of the table
49+
* @param selection : handles Where
50+
* @param selectionArgs : the condition of Where clause
51+
* @param sortOrder : ascending or descending
52+
*/
53+
@Override
54+
public Cursor query(@NonNull final Uri uri, final String[] projection, final String selection,
55+
final String[] selectionArgs, final String sortOrder) {
56+
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
57+
queryBuilder.setTables(TABLE_NAME);
58+
final SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
59+
final Cursor cursor = queryBuilder.query(db, projection, selection,
60+
selectionArgs, null, null, sortOrder);
61+
cursor.setNotificationUri(getContext().getContentResolver(), uri);
62+
return cursor;
63+
}
64+
65+
/**
66+
* Handles the update query of local SQLite Database
67+
* @param uri : contains the uri for recently used languages
68+
* @param contentValues : new values to be entered to db
69+
* @param selection : handles Where
70+
* @param selectionArgs : the condition of Where clause
71+
*/
72+
@Override
73+
public int update(@NonNull final Uri uri, final ContentValues contentValues,
74+
final String selection, final String[] selectionArgs) {
75+
final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
76+
final int rowsUpdated;
77+
if (TextUtils.isEmpty(selection)) {
78+
final int id = Integer.parseInt(uri.getLastPathSegment());
79+
rowsUpdated = sqlDB.update(TABLE_NAME,
80+
contentValues,
81+
COLUMN_NAME + " = ?",
82+
new String[]{String.valueOf(id)});
83+
} else {
84+
throw new IllegalArgumentException(
85+
"Parameter `selection` should be empty when updating an ID");
86+
}
87+
88+
getContext().getContentResolver().notifyChange(uri, null);
89+
return rowsUpdated;
90+
}
91+
92+
/**
93+
* Handles the insertion of new recently used languages record to local SQLite Database
94+
* @param uri : contains the uri for recently used languages
95+
* @param contentValues : new values to be entered to db
96+
*/
97+
@Override
98+
public Uri insert(@NonNull final Uri uri, final ContentValues contentValues) {
99+
final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
100+
final long id = sqlDB.insert(TABLE_NAME, null, contentValues);
101+
getContext().getContentResolver().notifyChange(uri, null);
102+
return Uri.parse(BASE_URI + "/" + id);
103+
}
104+
105+
/**
106+
* Handles the deletion of new recently used languages record to local SQLite Database
107+
* @param uri : contains the uri for recently used languages
108+
*/
109+
@Override
110+
public int delete(@NonNull final Uri uri, final String s, final String[] strings) {
111+
final int rows;
112+
final SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
113+
Timber.d("Deleting recently used language %s", uri.getLastPathSegment());
114+
rows = db.delete(
115+
TABLE_NAME,
116+
"language_code = ?",
117+
new String[]{uri.getLastPathSegment()}
118+
);
119+
getContext().getContentResolver().notifyChange(uri, null);
120+
return rows;
121+
}
122+
}

0 commit comments

Comments
 (0)