Commit 26e5926b authored by Shakti Sahu's avatar Shakti Sahu Committed by Commit Bot

Video Tutorials : Moved language to a server side concept

This CL
1 - Adds language struct to the proto consisting of name, native text,
  and locale.
2 - VideoTutorialService will still store the preferred locale in a
  pref which will be used as a key when iterating through the
  supporting languages.
3 - Removes the checked in strings for languages

TODO : Change server side proto

Bug: 1132161
Change-Id: I1483903e0615714aa790b6af1fbfaa4c6637c802
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2429979
Commit-Queue: Shakti Sahu <shaktisahu@chromium.org>
Reviewed-by: default avatarMin Qin <qinmin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811131}
parent ca51f973
...@@ -246,16 +246,6 @@ Still reading? ...@@ -246,16 +246,6 @@ Still reading?
<ignore regexp="The resource `R.string.video_tutorials_change_language` appears to be unused"/> <ignore regexp="The resource `R.string.video_tutorials_change_language` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_iph_tap_here_to_start` appears to be unused"/> <ignore regexp="The resource `R.string.video_tutorials_iph_tap_here_to_start` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_iph_tap_voice_icon_to_start` appears to be unused"/> <ignore regexp="The resource `R.string.video_tutorials_iph_tap_voice_icon_to_start` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_english` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_hindi` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_kannada` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_tamil` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_telugu` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_english_native_text` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_hindi_native_text` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_kannada_native_text` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_tamil_native_text` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_telugu_native_text` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_language_picker_title` appears to be unused"/> <ignore regexp="The resource `R.string.video_tutorials_language_picker_title` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_learn_chrome` appears to be unused"/> <ignore regexp="The resource `R.string.video_tutorials_learn_chrome` appears to be unused"/>
<ignore regexp="The resource `R.string.video_tutorials_popular_videos` appears to be unused"/> <ignore regexp="The resource `R.string.video_tutorials_popular_videos` appears to be unused"/>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import {$} from 'chrome://resources/js/util.m.js'; import {$} from 'chrome-untrusted://resources/js/util.m.js';
function onDocumentLoaded() { function onDocumentLoaded() {
// Find out the video, image, and caption urls from the url params. // Find out the video, image, and caption urls from the url params.
......
...@@ -2759,36 +2759,6 @@ In Incognito, your activity might still be visible to websites that you visit, y ...@@ -2759,36 +2759,6 @@ In Incognito, your activity might still be visible to websites that you visit, y
<message name="IDS_VIDEO_TUTORIALS_IPH_TAP_VOICE_ICON_TO_START" desc="In-product help bubble text prompting user to start typing on the search box or tap on the microphone icon to start a voice search."> <message name="IDS_VIDEO_TUTORIALS_IPH_TAP_VOICE_ICON_TO_START" desc="In-product help bubble text prompting user to start typing on the search box or tap on the microphone icon to start a voice search.">
Type here or tap the voice icon to start Type here or tap the voice icon to start
</message> </message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_ENGLISH" desc="Language option presented to the user in the video tutorial language picker. Shown in the system language script.">
English
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_ENGLISH_NATIVE_TEXT" desc="Language option presented to the user in the video tutorial language picker. Shown in the native script." translateable="false">
English
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_HINDI" desc="Language option presented to the user in the video tutorial language picker. Shown in the system language script.">
Hindi
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_HINDI_NATIVE_TEXT" desc="Language option presented to the user in the video tutorial language picker. Shown in the native script." translateable="false">
हिन्दी
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_TAMIL" desc="Language option presented to the user in the video tutorial language picker. Shown in the system language script.">
Tamil
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_TAMIL_NATIVE_TEXT" desc="Language option presented to the user in the video tutorial language picker. Shown in the native script." translateable="false">
தமிழ்
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_TELUGU" desc="Language option presented to the user in the video tutorial language picker. Shown in the system language script.">
Telugu
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_TELUGU_NATIVE_TEXT" desc="Language option presented to the user in the video tutorial language picker. Shown in the native script." translateable="false">
తెలుగు
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_KANNADA" desc="Language option presented to the user in the video tutorial language picker. Shown in the system language script.">
Kannada
</message>
<message name="IDS_VIDEO_TUTORIALS_LANGUAGE_KANNADA_NATIVE_TEXT" desc="Language option presented to the user in the video tutorial language picker. Shown in the native script." translateable="false">
ಕನ್ನಡ
</message>
<!-- Toolbar button strings --> <!-- Toolbar button strings -->
<message name="IDS_OPEN_TABS" desc="Text for button to enter the tab switcher and show tabs that are open on this device"> <message name="IDS_OPEN_TABS" desc="Text for button to enter the tab switcher and show tabs that are open on this device">
......
...@@ -55,6 +55,7 @@ source_set("factory") { ...@@ -55,6 +55,7 @@ source_set("factory") {
if (is_android) { if (is_android) {
android_library("java") { android_library("java") {
sources = [ sources = [
"android/java/src/org/chromium/chrome/browser/video_tutorials/Language.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialService.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialService.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinator.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinator.java",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.video_tutorials;
/**
* Class encapsulating data needed to show a language on the language selection UI.
*/
public class Language {
/** The locale associated with the language. */
public final String locale;
/** The name of the language. */
public final String name;
/** The name of the language in native text. */
public final String nativeName;
/** Constructor */
public Language(String locale, String name, String nativeName) {
this.locale = locale;
this.name = name;
this.nativeName = nativeName;
}
}
...@@ -26,7 +26,7 @@ public interface VideoTutorialService { ...@@ -26,7 +26,7 @@ public interface VideoTutorialService {
/** /**
* Called to get the list of supported languages. * Called to get the list of supported languages.
*/ */
List<String> getSupportedLanguages(); List<Language> getSupportedLanguages();
/** /**
* @return The user's language of choice for watching the video tutorials. * @return The user's language of choice for watching the video tutorials.
......
...@@ -70,7 +70,6 @@ if (is_android) { ...@@ -70,7 +70,6 @@ if (is_android) {
"android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerCoordinator.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerCoordinator.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerProperties.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerProperties.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerView.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerView.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageUtils.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinatorImpl.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinatorImpl.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java",
"android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java", "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java",
......
...@@ -8,6 +8,7 @@ import androidx.annotation.Nullable; ...@@ -8,6 +8,7 @@ import androidx.annotation.Nullable;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.chrome.browser.video_tutorials.Language;
import org.chromium.chrome.browser.video_tutorials.Tutorial; import org.chromium.chrome.browser.video_tutorials.Tutorial;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -19,7 +20,20 @@ import java.util.List; ...@@ -19,7 +20,20 @@ import java.util.List;
@JNINamespace("video_tutorials") @JNINamespace("video_tutorials")
public class TutorialConversionBridge { public class TutorialConversionBridge {
@CalledByNative @CalledByNative
private static List<Tutorial> createList() { private static List<Language> createLanguageList() {
return new ArrayList<>();
}
@CalledByNative
private static Language createLanguageAndMaybeAddToList(
@Nullable List<Language> list, String locale, String name, String nativeName) {
Language language = new Language(locale, name, nativeName);
if (list != null) list.add(language);
return language;
}
@CalledByNative
private static List<Tutorial> createTutorialList() {
return new ArrayList<>(); return new ArrayList<>();
} }
......
...@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative; ...@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.browser.video_tutorials.FeatureType; import org.chromium.chrome.browser.video_tutorials.FeatureType;
import org.chromium.chrome.browser.video_tutorials.Language;
import org.chromium.chrome.browser.video_tutorials.Tutorial; import org.chromium.chrome.browser.video_tutorials.Tutorial;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; import org.chromium.chrome.browser.video_tutorials.VideoTutorialService;
...@@ -45,9 +46,9 @@ public class VideoTutorialServiceBridge implements VideoTutorialService { ...@@ -45,9 +46,9 @@ public class VideoTutorialServiceBridge implements VideoTutorialService {
} }
@Override @Override
public List<String> getSupportedLanguages() { public List<Language> getSupportedLanguages() {
if (mNativeVideoTutorialServiceBridge == 0) return null; if (mNativeVideoTutorialServiceBridge == 0) return null;
return VideoTutorialServiceBridgeJni.get().getSupportedLocales( return VideoTutorialServiceBridgeJni.get().getSupportedLanguages(
mNativeVideoTutorialServiceBridge, this); mNativeVideoTutorialServiceBridge, this);
} }
...@@ -76,7 +77,7 @@ public class VideoTutorialServiceBridge implements VideoTutorialService { ...@@ -76,7 +77,7 @@ public class VideoTutorialServiceBridge implements VideoTutorialService {
Callback<List<Tutorial>> callback); Callback<List<Tutorial>> callback);
void getTutorial(long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller, void getTutorial(long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller,
int feature, Callback<Tutorial> callback); int feature, Callback<Tutorial> callback);
List<String> getSupportedLocales( List<Language> getSupportedLanguages(
long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller); long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller);
String getPreferredLocale( String getPreferredLocale(
long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller); long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller);
......
...@@ -9,6 +9,7 @@ import android.content.res.Resources; ...@@ -9,6 +9,7 @@ import android.content.res.Resources;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import org.chromium.chrome.browser.video_tutorials.Language;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; import org.chromium.chrome.browser.video_tutorials.VideoTutorialService;
import org.chromium.ui.modelutil.MVCListAdapter.ListItem; import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
...@@ -61,9 +62,9 @@ public class LanguagePickerCoordinator { ...@@ -61,9 +62,9 @@ public class LanguagePickerCoordinator {
populateList(mVideoTutorialService.getSupportedLanguages()); populateList(mVideoTutorialService.getSupportedLanguages());
} }
private void populateList(List<String> supportedLocales) { private void populateList(List<Language> supportedLanguages) {
List<ListItem> listItems = new ArrayList<>(); List<ListItem> listItems = new ArrayList<>();
for (String locale : supportedLocales) { for (Language locale : supportedLanguages) {
ListItem listItem = new ListItem( ListItem listItem = new ListItem(
LanguageItemProperties.ITEM_VIEW_TYPE, buildListItemModelFromLocale(locale)); LanguageItemProperties.ITEM_VIEW_TYPE, buildListItemModelFromLocale(locale));
listItems.add(listItem); listItems.add(listItem);
...@@ -71,16 +72,15 @@ public class LanguagePickerCoordinator { ...@@ -71,16 +72,15 @@ public class LanguagePickerCoordinator {
mListModel.set(listItems); mListModel.set(listItems);
} }
private PropertyModel buildListItemModelFromLocale(String locale) { private PropertyModel buildListItemModelFromLocale(Language language) {
Resources resources = mContext.getResources(); Resources resources = mContext.getResources();
String preferredLocale = mVideoTutorialService.getPreferredLocale(); String preferredLocale = mVideoTutorialService.getPreferredLocale();
return new PropertyModel.Builder(LanguageItemProperties.ALL_KEYS) return new PropertyModel.Builder(LanguageItemProperties.ALL_KEYS)
.with(LanguageItemProperties.LOCALE, locale) .with(LanguageItemProperties.LOCALE, language.locale)
.with(LanguageItemProperties.NAME, .with(LanguageItemProperties.NAME, language.name)
LanguageUtils.getLanguageForLocale(resources, locale)) .with(LanguageItemProperties.NATIVE_NAME, language.nativeName)
.with(LanguageItemProperties.NATIVE_NAME, .with(LanguageItemProperties.IS_SELECTED,
LanguageUtils.getLanguageForLocaleInNativeText(resources, locale)) TextUtils.equals(language.locale, preferredLocale))
.with(LanguageItemProperties.IS_SELECTED, TextUtils.equals(locale, preferredLocale))
.with(LanguageItemProperties.SELECTION_CALLBACK, this::onLanguageSelected) .with(LanguageItemProperties.SELECTION_CALLBACK, this::onLanguageSelected)
.build(); .build();
} }
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.video_tutorials.languages;
import android.content.res.Resources;
import android.text.TextUtils;
import org.chromium.chrome.browser.video_tutorials.R;
/**
* Utility class that provides methods for converting between locales and languages.
*/
public class LanguageUtils {
private static final String LOCALE_HINDI = "hi-IN";
private static final String LOCALE_TAMIL = "ta-IN";
private static final String LOCALE_TELUGU = "te-IN";
private static final String LOCALE_KANNADA = "kn-IN";
private static final String LOCALE_ENGLISH = "en-IN";
/** For a given locale, returns the name of the language in the native text. */
public static String getLanguageForLocaleInNativeText(Resources resources, String locale) {
if (TextUtils.equals(locale, LOCALE_HINDI)) {
return resources.getString(R.string.video_tutorials_language_hindi_native_text);
} else if (TextUtils.equals(locale, LOCALE_TAMIL)) {
return resources.getString(R.string.video_tutorials_language_tamil_native_text);
} else if (TextUtils.equals(locale, LOCALE_TELUGU)) {
return resources.getString(R.string.video_tutorials_language_telugu_native_text);
} else if (TextUtils.equals(locale, LOCALE_KANNADA)) {
return resources.getString(R.string.video_tutorials_language_kannada_native_text);
} else if (TextUtils.equals(locale, LOCALE_ENGLISH)) {
return resources.getString(R.string.video_tutorials_language_english_native_text);
}
return null;
}
/** For a given locale, returns the name of the language in the system text. */
public static String getLanguageForLocale(Resources resources, String locale) {
if (TextUtils.equals(locale, LOCALE_HINDI)) {
return resources.getString(R.string.video_tutorials_language_hindi);
} else if (TextUtils.equals(locale, LOCALE_TAMIL)) {
return resources.getString(R.string.video_tutorials_language_tamil);
} else if (TextUtils.equals(locale, LOCALE_TELUGU)) {
return resources.getString(R.string.video_tutorials_language_telugu);
} else if (TextUtils.equals(locale, LOCALE_KANNADA)) {
return resources.getString(R.string.video_tutorials_language_kannada);
} else if (TextUtils.equals(locale, LOCALE_ENGLISH)) {
return resources.getString(R.string.video_tutorials_language_english);
}
return null;
}
}
...@@ -5,14 +5,15 @@ ...@@ -5,14 +5,15 @@
package org.chromium.chrome.browser.video_tutorials.player; package org.chromium.chrome.browser.video_tutorials.player;
import android.content.Context; import android.content.Context;
import android.text.TextUtils;
import org.chromium.chrome.browser.video_tutorials.Language;
import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver; import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver;
import org.chromium.chrome.browser.video_tutorials.R; import org.chromium.chrome.browser.video_tutorials.R;
import org.chromium.chrome.browser.video_tutorials.Tutorial; import org.chromium.chrome.browser.video_tutorials.Tutorial;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; import org.chromium.chrome.browser.video_tutorials.VideoTutorialService;
import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils; import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils;
import org.chromium.chrome.browser.video_tutorials.languages.LanguagePickerCoordinator; import org.chromium.chrome.browser.video_tutorials.languages.LanguagePickerCoordinator;
import org.chromium.chrome.browser.video_tutorials.languages.LanguageUtils;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -97,11 +98,14 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer { ...@@ -97,11 +98,14 @@ class VideoPlayerMediator implements PlaybackStateObserver.Observer {
} }
private void updateChangeLanguageButtonText() { private void updateChangeLanguageButtonText() {
String language = LanguageUtils.getLanguageForLocale( String locale = mVideoTutorialService.getPreferredLocale();
mContext.getResources(), mVideoTutorialService.getPreferredLocale()); for (Language language : mVideoTutorialService.getSupportedLanguages()) {
String buttonText = mContext.getResources().getString( if (TextUtils.equals(language.locale, locale)) {
R.string.video_tutorials_change_language, language == null ? "" : language); String buttonText = mContext.getResources().getString(
mModel.set(VideoPlayerProperties.CHANGE_LANGUAGE_BUTTON_TEXT, buttonText); R.string.video_tutorials_change_language, language.nativeName);
mModel.set(VideoPlayerProperties.CHANGE_LANGUAGE_BUTTON_TEXT, buttonText);
}
}
} }
private void onLanguageSelected() { private void onLanguageSelected() {
......
...@@ -16,6 +16,28 @@ namespace video_tutorials { ...@@ -16,6 +16,28 @@ namespace video_tutorials {
using base::android::ConvertUTF8ToJavaString; using base::android::ConvertUTF8ToJavaString;
using base::android::ToJavaArrayOfStrings; using base::android::ToJavaArrayOfStrings;
ScopedJavaLocalRef<jobject> CreateJavaLanguageAndMaybeAddToList(
JNIEnv* env,
ScopedJavaLocalRef<jobject> jlist,
const Language& language) {
return Java_TutorialConversionBridge_createLanguageAndMaybeAddToList(
env, jlist, ConvertUTF8ToJavaString(env, language.locale),
ConvertUTF8ToJavaString(env, language.name),
ConvertUTF8ToJavaString(env, language.native_name));
}
ScopedJavaLocalRef<jobject> TutorialConversionBridge::CreateJavaLanguages(
JNIEnv* env,
const std::vector<Language>& languages) {
ScopedJavaLocalRef<jobject> jlist =
Java_TutorialConversionBridge_createLanguageList(env);
for (const auto& language : languages)
CreateJavaLanguageAndMaybeAddToList(env, jlist, language);
return jlist;
}
ScopedJavaLocalRef<jobject> CreateJavaTutorialAndMaybeAddToList( ScopedJavaLocalRef<jobject> CreateJavaTutorialAndMaybeAddToList(
JNIEnv* env, JNIEnv* env,
ScopedJavaLocalRef<jobject> jlist, ScopedJavaLocalRef<jobject> jlist,
...@@ -34,7 +56,7 @@ ScopedJavaLocalRef<jobject> TutorialConversionBridge::CreateJavaTutorials( ...@@ -34,7 +56,7 @@ ScopedJavaLocalRef<jobject> TutorialConversionBridge::CreateJavaTutorials(
JNIEnv* env, JNIEnv* env,
const std::vector<Tutorial>& tutorials) { const std::vector<Tutorial>& tutorials) {
ScopedJavaLocalRef<jobject> jlist = ScopedJavaLocalRef<jobject> jlist =
Java_TutorialConversionBridge_createList(env); Java_TutorialConversionBridge_createTutorialList(env);
for (const auto& tutorial : tutorials) for (const auto& tutorial : tutorials)
CreateJavaTutorialAndMaybeAddToList(env, jlist, tutorial); CreateJavaTutorialAndMaybeAddToList(env, jlist, tutorial);
......
...@@ -19,6 +19,10 @@ namespace video_tutorials { ...@@ -19,6 +19,10 @@ namespace video_tutorials {
// and Java. // and Java.
class TutorialConversionBridge { class TutorialConversionBridge {
public: public:
static ScopedJavaLocalRef<jobject> CreateJavaLanguages(
JNIEnv* env,
const std::vector<Language>& languages);
static ScopedJavaLocalRef<jobject> CreateJavaTutorials( static ScopedJavaLocalRef<jobject> CreateJavaTutorials(
JNIEnv* env, JNIEnv* env,
const std::vector<Tutorial>& tutorials); const std::vector<Tutorial>& tutorials);
......
...@@ -90,12 +90,11 @@ void VideoTutorialServiceBridge::GetTutorial( ...@@ -90,12 +90,11 @@ void VideoTutorialServiceBridge::GetTutorial(
ScopedJavaGlobalRef<jobject>(jcallback))); ScopedJavaGlobalRef<jobject>(jcallback)));
} }
ScopedJavaLocalRef<jobject> VideoTutorialServiceBridge::GetSupportedLocales( ScopedJavaLocalRef<jobject> VideoTutorialServiceBridge::GetSupportedLanguages(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& jcaller) { const JavaParamRef<jobject>& jcaller) {
std::vector<std::string> locales = return TutorialConversionBridge::CreateJavaLanguages(
video_tutorial_service_->GetSupportedLocales(); env, video_tutorial_service_->GetSupportedLanguages());
return base::android::ToJavaArrayOfStrings(env, locales);
} }
ScopedJavaLocalRef<jstring> VideoTutorialServiceBridge::GetPreferredLocale( ScopedJavaLocalRef<jstring> VideoTutorialServiceBridge::GetPreferredLocale(
......
...@@ -37,7 +37,7 @@ class VideoTutorialServiceBridge : public base::SupportsUserData::Data { ...@@ -37,7 +37,7 @@ class VideoTutorialServiceBridge : public base::SupportsUserData::Data {
const JavaParamRef<jobject>& jcaller, const JavaParamRef<jobject>& jcaller,
jint j_feature, jint j_feature,
const JavaParamRef<jobject>& jcallback); const JavaParamRef<jobject>& jcallback);
ScopedJavaLocalRef<jobject> GetSupportedLocales( ScopedJavaLocalRef<jobject> GetSupportedLanguages(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& jcaller); const JavaParamRef<jobject>& jcaller);
ScopedJavaLocalRef<jstring> GetPreferredLocale( ScopedJavaLocalRef<jstring> GetPreferredLocale(
......
...@@ -47,6 +47,22 @@ proto::FeatureType FromFeatureType(FeatureType type) { ...@@ -47,6 +47,22 @@ proto::FeatureType FromFeatureType(FeatureType type) {
} // namespace } // namespace
void LanguageToProto(Language* language, LanguageProto* proto) {
DCHECK(language);
DCHECK(proto);
proto->set_locale(language->locale);
proto->set_name(language->name);
proto->set_native_name(language->native_name);
}
void LanguageFromProto(LanguageProto* proto, Language* language) {
DCHECK(language);
DCHECK(proto);
language->locale = proto->locale();
language->name = proto->name();
language->native_name = proto->native_name();
}
void TutorialToProto(Tutorial* tutorial, TutorialProto* proto) { void TutorialToProto(Tutorial* tutorial, TutorialProto* proto) {
DCHECK(tutorial); DCHECK(tutorial);
DCHECK(proto); DCHECK(proto);
...@@ -74,7 +90,7 @@ void TutorialFromProto(TutorialProto* proto, Tutorial* tutorial) { ...@@ -74,7 +90,7 @@ void TutorialFromProto(TutorialProto* proto, Tutorial* tutorial) {
void TutorialGroupToProto(TutorialGroup* group, TutorialGroupProto* proto) { void TutorialGroupToProto(TutorialGroup* group, TutorialGroupProto* proto) {
DCHECK(group); DCHECK(group);
DCHECK(proto); DCHECK(proto);
proto->set_locale(group->locale); LanguageToProto(&group->language, proto->mutable_language());
proto->clear_tutorials(); proto->clear_tutorials();
for (auto& tutorial : group->tutorials) for (auto& tutorial : group->tutorials)
TutorialToProto(&tutorial, proto->add_tutorials()); TutorialToProto(&tutorial, proto->add_tutorials());
...@@ -83,7 +99,7 @@ void TutorialGroupToProto(TutorialGroup* group, TutorialGroupProto* proto) { ...@@ -83,7 +99,7 @@ void TutorialGroupToProto(TutorialGroup* group, TutorialGroupProto* proto) {
void TutorialGroupFromProto(TutorialGroupProto* proto, TutorialGroup* group) { void TutorialGroupFromProto(TutorialGroupProto* proto, TutorialGroup* group) {
DCHECK(group); DCHECK(group);
DCHECK(proto); DCHECK(proto);
group->locale = proto->locale(); LanguageFromProto(proto->mutable_language(), &group->language);
group->tutorials.clear(); group->tutorials.clear();
for (auto tutorial_proto : proto->tutorials()) { for (auto tutorial_proto : proto->tutorials()) {
Tutorial tutorial; Tutorial tutorial;
......
...@@ -10,9 +10,16 @@ ...@@ -10,9 +10,16 @@
namespace video_tutorials { namespace video_tutorials {
using LanguageProto = video_tutorials::proto::Language;
using TutorialProto = video_tutorials::proto::VideoTutorial; using TutorialProto = video_tutorials::proto::VideoTutorial;
using TutorialGroupProto = video_tutorials::proto::VideoTutorialGroup; using TutorialGroupProto = video_tutorials::proto::VideoTutorialGroup;
// Convert in-memory struct Language to proto::Language.
void LanguageToProto(Language* language, LanguageProto* proto);
// Convert proto::Language to in-memory struct Language.
void LanguageFromProto(LanguageProto* proto, Language* language);
// Convert in-memory struct Tutorial to proto::VideoTutorial. // Convert in-memory struct Tutorial to proto::VideoTutorial.
void TutorialToProto(Tutorial* tutorial, TutorialProto* proto); void TutorialToProto(Tutorial* tutorial, TutorialProto* proto);
......
...@@ -20,16 +20,16 @@ namespace video_tutorials { ...@@ -20,16 +20,16 @@ namespace video_tutorials {
template <typename T> template <typename T>
class Store { class Store {
public: public:
using Keys = std::unique_ptr<std::vector<std::string>>; using Entries = std::unique_ptr<std::vector<T>>;
using Entries = std::vector<std::unique_ptr<T>>; using SuccessCallback = base::OnceCallback<void(bool)>;
using LoadKeysCallback = base::OnceCallback<void(bool, Keys)>;
using LoadEntriesCallback = base::OnceCallback<void(bool, Entries)>; using LoadEntriesCallback = base::OnceCallback<void(bool, Entries)>;
using UpdateCallback = base::OnceCallback<void(bool)>; using UpdateCallback = base::OnceCallback<void(bool)>;
// Initialize the db and load keys into memory. // Initialize the db and load entries into memory.
virtual void InitAndLoadKeys(LoadKeysCallback callback) = 0; virtual void Initialize(SuccessCallback callback) = 0;
// Load entries with the given keys into memory. // Load entries with the given keys into memory. If |keys| is empty, load all
// the entries.
virtual void LoadEntries(const std::vector<std::string>& keys, virtual void LoadEntries(const std::vector<std::string>& keys,
LoadEntriesCallback callback) = 0; LoadEntriesCallback callback) = 0;
......
...@@ -8,10 +8,10 @@ namespace video_tutorials { ...@@ -8,10 +8,10 @@ namespace video_tutorials {
TutorialGroup::TutorialGroup() = default; TutorialGroup::TutorialGroup() = default;
TutorialGroup::TutorialGroup(const std::string& locale) : locale(locale) {} TutorialGroup::TutorialGroup(const Language& language) : language(language) {}
bool TutorialGroup::operator==(const TutorialGroup& other) const { bool TutorialGroup::operator==(const TutorialGroup& other) const {
return locale == other.locale && tutorials == other.tutorials; return language == other.language && tutorials == other.tutorials;
} }
bool TutorialGroup::operator!=(const TutorialGroup& other) const { bool TutorialGroup::operator!=(const TutorialGroup& other) const {
......
...@@ -12,7 +12,7 @@ namespace video_tutorials { ...@@ -12,7 +12,7 @@ namespace video_tutorials {
// In memory struct of a group of video tutorials with same language . // In memory struct of a group of video tutorials with same language .
struct TutorialGroup { struct TutorialGroup {
TutorialGroup(); TutorialGroup();
explicit TutorialGroup(const std::string& locale); explicit TutorialGroup(const Language& language);
~TutorialGroup(); ~TutorialGroup();
bool operator==(const TutorialGroup& other) const; bool operator==(const TutorialGroup& other) const;
...@@ -22,7 +22,7 @@ struct TutorialGroup { ...@@ -22,7 +22,7 @@ struct TutorialGroup {
TutorialGroup& operator=(const TutorialGroup& other); TutorialGroup& operator=(const TutorialGroup& other);
// Language of this group. // Language of this group.
std::string locale; Language language;
// A list of tutorials. // A list of tutorials.
std::vector<Tutorial> tutorials; std::vector<Tutorial> tutorials;
......
...@@ -10,7 +10,9 @@ namespace video_tutorials { ...@@ -10,7 +10,9 @@ namespace video_tutorials {
namespace { namespace {
void ResetTutorialGroup(TutorialGroup* group) { void ResetTutorialGroup(TutorialGroup* group) {
*group = TutorialGroup("en"); Language language;
language.locale = "en";
*group = TutorialGroup(language);
group->tutorials.resize(3, Tutorial()); group->tutorials.resize(3, Tutorial());
group->tutorials.front().feature = FeatureType::kDownload; group->tutorials.front().feature = FeatureType::kDownload;
group->tutorials.back().feature = FeatureType::kSearch; group->tutorials.back().feature = FeatureType::kSearch;
...@@ -24,7 +26,7 @@ TEST(VideoTutorialGroupTest, CopyAndCompareOperators) { ...@@ -24,7 +26,7 @@ TEST(VideoTutorialGroupTest, CopyAndCompareOperators) {
EXPECT_EQ(lhs, rhs); EXPECT_EQ(lhs, rhs);
rhs.locale = "jp"; rhs.language.locale = "jp";
EXPECT_NE(lhs, rhs); EXPECT_NE(lhs, rhs);
ResetTutorialGroup(&rhs); ResetTutorialGroup(&rhs);
......
...@@ -17,16 +17,12 @@ class TutorialManager { ...@@ -17,16 +17,12 @@ class TutorialManager {
using SuccessCallback = base::OnceCallback<void(bool)>; using SuccessCallback = base::OnceCallback<void(bool)>;
using GetTutorialsCallback = base::OnceCallback<void(std::vector<Tutorial>)>; using GetTutorialsCallback = base::OnceCallback<void(std::vector<Tutorial>)>;
// Initialization method that reads the database and loads video tutorials
// into in-memory.
virtual void Init(SuccessCallback callback) = 0;
// Loads video tutorials. Must be called again if the locale was changed by // Loads video tutorials. Must be called again if the locale was changed by
// the user. // the user.
virtual void GetTutorials(GetTutorialsCallback callback) = 0; virtual void GetTutorials(GetTutorialsCallback callback) = 0;
// Returns a list of locales for which video tutorials are available. // Returns a list of languages for which video tutorials are available.
virtual const std::vector<std::string>& GetSupportedLocales() = 0; virtual const std::vector<Language>& GetSupportedLanguages() = 0;
// Returns the preferred locale for the video tutorials. // Returns the preferred locale for the video tutorials.
virtual std::string GetPreferredLocale() = 0; virtual std::string GetPreferredLocale() = 0;
...@@ -38,7 +34,7 @@ class TutorialManager { ...@@ -38,7 +34,7 @@ class TutorialManager {
// Saves a fresh set of video tutorials into database. Called after a network // Saves a fresh set of video tutorials into database. Called after a network
// fetch. // fetch.
virtual void SaveGroups(std::vector<std::unique_ptr<TutorialGroup>> groups, virtual void SaveGroups(std::unique_ptr<std::vector<TutorialGroup>> groups,
SuccessCallback callback) = 0; SuccessCallback callback) = 0;
virtual ~TutorialManager() = default; virtual ~TutorialManager() = default;
......
...@@ -16,20 +16,29 @@ namespace video_tutorials { ...@@ -16,20 +16,29 @@ namespace video_tutorials {
TutorialManagerImpl::TutorialManagerImpl(std::unique_ptr<TutorialStore> store, TutorialManagerImpl::TutorialManagerImpl(std::unique_ptr<TutorialStore> store,
PrefService* prefs) PrefService* prefs)
: store_(std::move(store)), prefs_(prefs) {} : store_(std::move(store)), prefs_(prefs) {
Initialize();
}
TutorialManagerImpl::~TutorialManagerImpl() = default; TutorialManagerImpl::~TutorialManagerImpl() = default;
void TutorialManagerImpl::Init(SuccessCallback callback) { void TutorialManagerImpl::Initialize() {
store_->InitAndLoadKeys(base::BindOnce(&TutorialManagerImpl::OnInitCompleted, store_->Initialize(base::BindOnce(&TutorialManagerImpl::OnInitCompleted,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr()));
std::move(callback)));
} }
void TutorialManagerImpl::GetTutorials(GetTutorialsCallback callback) { void TutorialManagerImpl::GetTutorials(GetTutorialsCallback callback) {
if (!init_success_.has_value()) {
MaybeCacheApiCall(base::BindOnce(&TutorialManagerImpl::GetTutorials,
weak_ptr_factory_.GetWeakPtr(),
std::move(callback)));
return;
}
// Find the data from cache. // Find the data from cache.
std::string locale = GetPreferredLocale(); std::string locale = GetPreferredLocale();
if (tutorial_group_ && tutorial_group_->locale == locale) { if (tutorial_group_.has_value() &&
tutorial_group_->language.locale == locale) {
std::move(callback).Run(tutorial_group_->tutorials); std::move(callback).Run(tutorial_group_->tutorials);
return; return;
} }
...@@ -42,8 +51,8 @@ void TutorialManagerImpl::GetTutorials(GetTutorialsCallback callback) { ...@@ -42,8 +51,8 @@ void TutorialManagerImpl::GetTutorials(GetTutorialsCallback callback) {
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
const std::vector<std::string>& TutorialManagerImpl::GetSupportedLocales() { const std::vector<Language>& TutorialManagerImpl::GetSupportedLanguages() {
return supported_locales_; return supported_languages_;
} }
std::string TutorialManagerImpl::GetPreferredLocale() { std::string TutorialManagerImpl::GetPreferredLocale() {
...@@ -56,56 +65,84 @@ void TutorialManagerImpl::SetPreferredLocale(const std::string& locale) { ...@@ -56,56 +65,84 @@ void TutorialManagerImpl::SetPreferredLocale(const std::string& locale) {
prefs_->SetString(kPreferredLocaleKey, locale); prefs_->SetString(kPreferredLocaleKey, locale);
} }
void TutorialManagerImpl::OnInitCompleted( void TutorialManagerImpl::OnInitCompleted(bool success) {
SuccessCallback callback, if (!success)
bool success,
std::unique_ptr<std::vector<std::string>> supported_locales) {
if (!success) {
std::move(callback).Run(success);
return; return;
store_->LoadEntries({},
base::BindOnce(&TutorialManagerImpl::OnInitialDataLoaded,
weak_ptr_factory_.GetWeakPtr()));
}
void TutorialManagerImpl::OnInitialDataLoaded(
bool success,
std::unique_ptr<std::vector<TutorialGroup>> all_groups) {
if (all_groups) {
for (auto& tutorial_group : *all_groups) {
supported_languages_.emplace_back(tutorial_group.language);
}
} }
if (supported_locales) DCHECK(!init_success_.has_value());
supported_locales_ = *supported_locales.get(); init_success_ = success;
std::move(callback).Run(true); // Flush all cached calls in FIFO sequence.
while (!cached_api_calls_.empty()) {
auto api_call = std::move(cached_api_calls_.front());
cached_api_calls_.pop_front();
std::move(api_call).Run();
}
} }
void TutorialManagerImpl::OnTutorialsLoaded( void TutorialManagerImpl::OnTutorialsLoaded(
GetTutorialsCallback callback, GetTutorialsCallback callback,
bool success, bool success,
std::vector<std::unique_ptr<TutorialGroup>> loaded_group) { std::unique_ptr<std::vector<TutorialGroup>> loaded_groups) {
if (!success || loaded_group.empty()) { if (!success || !loaded_groups || loaded_groups->empty()) {
std::move(callback).Run(std::vector<Tutorial>()); std::move(callback).Run(std::vector<Tutorial>());
return; return;
} }
if (!init_success_.has_value()) {
MaybeCacheApiCall(base::BindOnce(
&TutorialManagerImpl::OnTutorialsLoaded, weak_ptr_factory_.GetWeakPtr(),
std::move(callback), success, std::move(loaded_groups)));
return;
}
// We are loading tutorials only for the preferred locale. // We are loading tutorials only for the preferred locale.
DCHECK(loaded_group.size() == 1u); DCHECK(loaded_groups->size() == 1u);
tutorial_group_ = std::move(loaded_group.front()); tutorial_group_ = loaded_groups->front();
std::move(callback).Run(tutorial_group_->tutorials); std::move(callback).Run(tutorial_group_->tutorials);
} }
void TutorialManagerImpl::SaveGroups( void TutorialManagerImpl::SaveGroups(
std::vector<std::unique_ptr<TutorialGroup>> groups, std::unique_ptr<std::vector<TutorialGroup>> groups,
SuccessCallback callback) { SuccessCallback callback) {
std::vector<std::string> new_locales; std::vector<std::string> new_locales;
std::vector<std::pair<std::string, TutorialGroup>> key_entry_pairs; std::vector<std::pair<std::string, TutorialGroup>> key_entry_pairs;
for (auto& group : groups) { for (auto& group : *groups.get()) {
new_locales.emplace_back(group->locale); new_locales.emplace_back(group.language.locale);
key_entry_pairs.emplace_back(std::make_pair(group->locale, *group)); key_entry_pairs.emplace_back(std::make_pair(group.language.locale, group));
} }
// Remove the locales that don't exist in the new data. // Remove the languages that don't exist in the new data.
// TODO(shaktisahu): Maybe completely nuke the DB and save new data.
std::vector<std::string> keys_to_delete; std::vector<std::string> keys_to_delete;
for (auto& old_locale : supported_locales_) { for (auto& old_language : supported_languages_) {
if (std::find(new_locales.begin(), new_locales.end(), old_locale) == if (std::find(new_locales.begin(), new_locales.end(),
new_locales.end()) { old_language.locale) == new_locales.end()) {
keys_to_delete.emplace_back(old_locale); keys_to_delete.emplace_back(old_language.locale);
} }
} }
store_->UpdateAll(key_entry_pairs, keys_to_delete, std::move(callback)); store_->UpdateAll(key_entry_pairs, keys_to_delete, std::move(callback));
} }
void TutorialManagerImpl::MaybeCacheApiCall(base::OnceClosure api_call) {
DCHECK(!init_success_.has_value())
<< "Only cache API calls before initialization.";
cached_api_calls_.emplace_back(std::move(api_call));
}
} // namespace video_tutorials } // namespace video_tutorials
...@@ -7,11 +7,13 @@ ...@@ -7,11 +7,13 @@
#include "chrome/browser/video_tutorials/internal/tutorial_manager.h" #include "chrome/browser/video_tutorials/internal/tutorial_manager.h"
#include <deque>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chrome/browser/video_tutorials/internal/store.h" #include "chrome/browser/video_tutorials/internal/store.h"
class PrefService; class PrefService;
...@@ -26,32 +28,38 @@ class TutorialManagerImpl : public TutorialManager { ...@@ -26,32 +28,38 @@ class TutorialManagerImpl : public TutorialManager {
private: private:
// TutorialManager implementation. // TutorialManager implementation.
void Init(SuccessCallback callback) override;
void GetTutorials(GetTutorialsCallback callback) override; void GetTutorials(GetTutorialsCallback callback) override;
const std::vector<std::string>& GetSupportedLocales() override; const std::vector<Language>& GetSupportedLanguages() override;
std::string GetPreferredLocale() override; std::string GetPreferredLocale() override;
void SetPreferredLocale(const std::string& locale) override; void SetPreferredLocale(const std::string& locale) override;
void SaveGroups(std::vector<std::unique_ptr<TutorialGroup>> groups, void SaveGroups(std::unique_ptr<std::vector<TutorialGroup>> groups,
SuccessCallback callback) override; SuccessCallback callback) override;
void OnInitCompleted( void Initialize();
SuccessCallback callback, void OnInitCompleted(bool success);
void OnInitialDataLoaded(
bool success, bool success,
std::unique_ptr<std::vector<std::string>> supported_locales); std::unique_ptr<std::vector<TutorialGroup>> all_groups);
void MaybeCacheApiCall(base::OnceClosure api_call);
void OnTutorialsLoaded( void OnTutorialsLoaded(
GetTutorialsCallback callback, GetTutorialsCallback callback,
bool success, bool success,
std::vector<std::unique_ptr<TutorialGroup>> loaded_group); std::unique_ptr<std::vector<TutorialGroup>> loaded_groups);
std::unique_ptr<TutorialStore> store_; std::unique_ptr<TutorialStore> store_;
PrefService* prefs_; PrefService* prefs_;
// List of locales for which we have tutorials. // List of languages for which we have tutorials.
std::vector<std::string> supported_locales_; std::vector<Language> supported_languages_;
// We only keep the tutorials for the preferred locale. // We only keep the tutorials for the preferred locale.
std::unique_ptr<TutorialGroup> tutorial_group_; base::Optional<TutorialGroup> tutorial_group_;
// The initialization result of the database.
base::Optional<bool> init_success_;
// Caches the API calls in case initialization is not completed.
std::deque<base::OnceClosure> cached_api_calls_;
base::WeakPtrFactory<TutorialManagerImpl> weak_ptr_factory_{this}; base::WeakPtrFactory<TutorialManagerImpl> weak_ptr_factory_{this};
}; };
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "chrome/browser/video_tutorials/prefs.h"
#include "components/prefs/testing_pref_service.h" #include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -26,7 +27,7 @@ std::vector<TutorialGroup> CreateSampleGroups( ...@@ -26,7 +27,7 @@ std::vector<TutorialGroup> CreateSampleGroups(
std::vector<TutorialGroup> groups; std::vector<TutorialGroup> groups;
for (const auto& locale : locales) { for (const auto& locale : locales) {
TutorialGroup group; TutorialGroup group;
group.locale = locale; group.language.locale = locale;
group.tutorials.emplace_back(Tutorial()); group.tutorials.emplace_back(Tutorial());
group.tutorials.emplace_back(Tutorial()); group.tutorials.emplace_back(Tutorial());
groups.emplace_back(group); groups.emplace_back(group);
...@@ -35,11 +36,11 @@ std::vector<TutorialGroup> CreateSampleGroups( ...@@ -35,11 +36,11 @@ std::vector<TutorialGroup> CreateSampleGroups(
return groups; return groups;
} }
std::vector<std::unique_ptr<TutorialGroup>> CreateSampleFetchData( std::unique_ptr<std::vector<TutorialGroup>> CreateSampleFetchData(
const std::vector<std::string>& locales) { const std::vector<std::string>& locales) {
std::vector<std::unique_ptr<TutorialGroup>> groups; auto groups = std::make_unique<std::vector<TutorialGroup>>();
for (const auto& group : CreateSampleGroups(locales)) { for (const auto& group : CreateSampleGroups(locales)) {
groups.emplace_back(std::make_unique<TutorialGroup>(group)); groups->emplace_back(group);
} }
return groups; return groups;
...@@ -50,29 +51,30 @@ class TestStore : public Store<TutorialGroup> { ...@@ -50,29 +51,30 @@ class TestStore : public Store<TutorialGroup> {
TestStore() = default; TestStore() = default;
~TestStore() override = default; ~TestStore() override = default;
void InitAndLoadKeys(LoadKeysCallback callback) override { void Initialize(SuccessCallback callback) override {
std::vector<std::string> keys; std::move(callback).Run(true);
for (const TutorialGroup& group : groups_)
keys.emplace_back(group.locale);
std::move(callback).Run(true,
std::make_unique<std::vector<std::string>>(keys));
} }
void LoadEntries(const std::vector<std::string>& keys, void LoadEntries(const std::vector<std::string>& keys,
LoadEntriesCallback callback) override { LoadEntriesCallback callback) override {
std::vector<std::unique_ptr<TutorialGroup>> entries; auto entries = std::make_unique<std::vector<TutorialGroup>>();
for (const TutorialGroup& group : groups_) { for (const TutorialGroup& group : groups_) {
if (group.locale != locale_) if (keys.empty()) {
continue; entries->emplace_back(group);
entries.emplace_back(std::make_unique<TutorialGroup>(group)); } else {
for (auto& key : keys) {
if (key == group.language.locale) {
entries->emplace_back(group);
}
}
}
} }
std::move(callback).Run(true, std::move(entries)); std::move(callback).Run(true, std::move(entries));
} }
void Initialize(const std::string& locale, void InitStoreData(const std::string& locale,
const std::vector<TutorialGroup>& groups) { const std::vector<TutorialGroup>& groups) {
locale_ = locale; locale_ = locale;
groups_ = groups; groups_ = groups;
} }
...@@ -101,8 +103,9 @@ class TutorialManagerTest : public testing::Test { ...@@ -101,8 +103,9 @@ class TutorialManagerTest : public testing::Test {
TutorialManagerTest(const TutorialManagerTest& other) = delete; TutorialManagerTest(const TutorialManagerTest& other) = delete;
TutorialManagerTest& operator=(const TutorialManagerTest& other) = delete; TutorialManagerTest& operator=(const TutorialManagerTest& other) = delete;
void SetUp() override { void SetUp() override { video_tutorials::RegisterPrefs(prefs_.registry()); }
auto tutorial_store = std::make_unique<StrictMock<TestStore>>();
void CreateTutorialManager(std::unique_ptr<TestStore> tutorial_store) {
tutorial_store_ = tutorial_store.get(); tutorial_store_ = tutorial_store.get();
manager_ = std::make_unique<TutorialManagerImpl>(std::move(tutorial_store), manager_ = std::make_unique<TutorialManagerImpl>(std::move(tutorial_store),
&prefs_); &prefs_);
...@@ -110,33 +113,25 @@ class TutorialManagerTest : public testing::Test { ...@@ -110,33 +113,25 @@ class TutorialManagerTest : public testing::Test {
// Run GetTutorials call from manager_, compare the |expected| to the actual // Run GetTutorials call from manager_, compare the |expected| to the actual
// returned tutorials. // returned tutorials.
void GetTutorials(std::vector<Tutorial> expected) { void GetTutorials() {
base::RunLoop loop; base::RunLoop loop;
manager()->GetTutorials(base::BindOnce( manager()->GetTutorials(base::BindOnce(&TutorialManagerTest::OnGetTutorials,
&TutorialManagerTest::OnGetTutorials, base::Unretained(this), base::Unretained(this),
loop.QuitClosure(), std::move(expected))); loop.QuitClosure()));
loop.Run(); loop.Run();
} }
void OnGetTutorials(base::RepeatingClosure closure, void OnGetTutorials(base::RepeatingClosure closure,
std::vector<Tutorial> expected,
std::vector<Tutorial> tutorials) { std::vector<Tutorial> tutorials) {
EXPECT_TRUE(expected.size() == tutorials.size()); last_results_ = tutorials;
std::move(closure).Run(); std::move(closure).Run();
} }
void Init() {
base::RunLoop loop;
manager()->Init(base::BindOnce(&TutorialManagerTest::OnComplete,
base::Unretained(this), loop.QuitClosure()));
loop.Run();
}
void OnComplete(base::RepeatingClosure closure, bool success) { void OnComplete(base::RepeatingClosure closure, bool success) {
std::move(closure).Run(); std::move(closure).Run();
} }
void SaveGroups(std::vector<std::unique_ptr<TutorialGroup>> groups) { void SaveGroups(std::unique_ptr<std::vector<TutorialGroup>> groups) {
base::RunLoop loop; base::RunLoop loop;
manager()->SaveGroups( manager()->SaveGroups(
std::move(groups), std::move(groups),
...@@ -148,35 +143,45 @@ class TutorialManagerTest : public testing::Test { ...@@ -148,35 +143,45 @@ class TutorialManagerTest : public testing::Test {
protected: protected:
TutorialManager* manager() { return manager_.get(); } TutorialManager* manager() { return manager_.get(); }
TestStore* tutorial_store() { return tutorial_store_; } TestStore* tutorial_store() { return tutorial_store_; }
std::vector<Tutorial> last_results() { return last_results_; }
private: private:
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
TestingPrefServiceSimple prefs_; TestingPrefServiceSimple prefs_;
std::unique_ptr<TutorialManager> manager_; std::unique_ptr<TutorialManager> manager_;
TestStore* tutorial_store_; TestStore* tutorial_store_;
std::vector<Tutorial> last_results_;
}; };
TEST_F(TutorialManagerTest, InitAndGetTutorials) { TEST_F(TutorialManagerTest, InitAndGetTutorials) {
auto groups = CreateSampleGroups({"hi", "kn"}); auto groups = CreateSampleGroups({"hi", "kn"});
tutorial_store()->Initialize("hi", groups); auto tutorial_store = std::make_unique<StrictMock<TestStore>>();
Init(); tutorial_store->InitStoreData("hi", groups);
CreateTutorialManager(std::move(tutorial_store));
auto locales = manager()->GetSupportedLocales();
EXPECT_EQ(locales.size(), 2u); auto languages = manager()->GetSupportedLanguages();
GetTutorials(groups[0].tutorials); EXPECT_EQ(languages.size(), 2u);
GetTutorials();
EXPECT_EQ(last_results().size(), 2u);
} }
TEST_F(TutorialManagerTest, SaveNewData) { TEST_F(TutorialManagerTest, SaveNewData) {
auto groups = CreateSampleGroups({"hi", "kn"}); auto groups = CreateSampleGroups({"hi", "kn"});
tutorial_store()->Initialize("hi", groups); auto tutorial_store = std::make_unique<StrictMock<TestStore>>();
Init(); tutorial_store->InitStoreData("hi", groups);
CreateTutorialManager(std::move(tutorial_store));
auto locales = manager()->GetSupportedLocales(); auto languages = manager()->GetSupportedLanguages();
EXPECT_EQ(locales.size(), 2u); EXPECT_EQ(languages.size(), 2u);
GetTutorials(groups[0].tutorials); GetTutorials();
EXPECT_EQ(last_results().size(), groups[0].tutorials.size());
auto new_groups = CreateSampleFetchData({"hi", "tl", "ar"}); auto new_groups = CreateSampleFetchData({"hi", "tl", "ar"});
auto new_group = new_groups->at(0);
SaveGroups(std::move(new_groups)); SaveGroups(std::move(new_groups));
manager()->SetPreferredLocale("ar");
GetTutorials();
EXPECT_EQ(last_results().size(), new_group.tutorials.size());
} }
} // namespace } // namespace
......
...@@ -63,8 +63,8 @@ void TutorialServiceImpl::OnFetchFinished( ...@@ -63,8 +63,8 @@ void TutorialServiceImpl::OnFetchFinished(
// TODO(shaktisahu): Save tutorials to the database. // TODO(shaktisahu): Save tutorials to the database.
} }
std::vector<std::string> TutorialServiceImpl::GetSupportedLocales() { const std::vector<Language>& TutorialServiceImpl::GetSupportedLanguages() {
return tutorial_manager_->GetSupportedLocales(); return tutorial_manager_->GetSupportedLanguages();
} }
std::string TutorialServiceImpl::GetPreferredLocale() { std::string TutorialServiceImpl::GetPreferredLocale() {
......
...@@ -25,7 +25,7 @@ class TutorialServiceImpl : public VideoTutorialService { ...@@ -25,7 +25,7 @@ class TutorialServiceImpl : public VideoTutorialService {
void GetTutorials(MultipleItemCallback callback) override; void GetTutorials(MultipleItemCallback callback) override;
void GetTutorial(FeatureType feature_type, void GetTutorial(FeatureType feature_type,
SingleItemCallback callback) override; SingleItemCallback callback) override;
std::vector<std::string> GetSupportedLocales() override; const std::vector<Language>& GetSupportedLanguages() override;
std::string GetPreferredLocale() override; std::string GetPreferredLocale() override;
void SetPreferredLocale(const std::string& locale) override; void SetPreferredLocale(const std::string& locale) override;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "base/logging.h"
#include "base/stl_util.h" #include "base/stl_util.h"
namespace leveldb_proto { namespace leveldb_proto {
...@@ -28,7 +29,7 @@ TutorialStore::TutorialStore(TutorialProtoDb db) : db_(std::move(db)) {} ...@@ -28,7 +29,7 @@ TutorialStore::TutorialStore(TutorialProtoDb db) : db_(std::move(db)) {}
TutorialStore::~TutorialStore() = default; TutorialStore::~TutorialStore() = default;
void TutorialStore::InitAndLoadKeys(LoadKeysCallback callback) { void TutorialStore::Initialize(SuccessCallback callback) {
db_->Init(base::BindOnce(&TutorialStore::OnDbInitialized, db_->Init(base::BindOnce(&TutorialStore::OnDbInitialized,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
std::move(callback))); std::move(callback)));
...@@ -36,14 +37,19 @@ void TutorialStore::InitAndLoadKeys(LoadKeysCallback callback) { ...@@ -36,14 +37,19 @@ void TutorialStore::InitAndLoadKeys(LoadKeysCallback callback) {
void TutorialStore::LoadEntries(const std::vector<std::string>& keys, void TutorialStore::LoadEntries(const std::vector<std::string>& keys,
LoadEntriesCallback callback) { LoadEntriesCallback callback) {
if (keys.empty()) {
// Load all entries.
db_->LoadEntries(std::move(callback));
return;
}
db_->LoadEntriesWithFilter( db_->LoadEntriesWithFilter(
base::BindRepeating( base::BindRepeating(
[](const std::vector<std::string>& key_dict, const std::string& key) { [](const std::vector<std::string>& key_dict, const std::string& key) {
return base::Contains(key_dict, key); return base::Contains(key_dict, key);
}, },
keys), keys),
base::BindOnce(&TutorialStore::OnEntriesLoaded, std::move(callback));
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void TutorialStore::UpdateAll( void TutorialStore::UpdateAll(
...@@ -62,36 +68,9 @@ void TutorialStore::UpdateAll( ...@@ -62,36 +68,9 @@ void TutorialStore::UpdateAll(
std::move(callback)); std::move(callback));
} }
void TutorialStore::OnDbInitialized(LoadKeysCallback callback, void TutorialStore::OnDbInitialized(SuccessCallback callback,
leveldb_proto::Enums::InitStatus status) { leveldb_proto::Enums::InitStatus status) {
if (status != leveldb_proto::Enums::InitStatus::kOK) { std::move(callback).Run(status == leveldb_proto::Enums::InitStatus::kOK);
std::move(callback).Run(false, Keys());
return;
}
db_->LoadKeys(base::BindOnce(&TutorialStore::OnKeysLoaded,
weak_ptr_factory_.GetWeakPtr(),
std::move(callback)));
}
void TutorialStore::OnKeysLoaded(LoadKeysCallback callback,
bool success,
std::unique_ptr<KeyVector> keys) {
std::move(callback).Run(success, success ? std::move(keys) : Keys());
}
void TutorialStore::OnEntriesLoaded(
LoadEntriesCallback callback,
bool success,
std::unique_ptr<std::vector<TutorialGroup>> loaded_entries) {
if (!success || !loaded_entries) {
std::move(callback).Run(success, Entries());
return;
}
Entries entries;
for (auto& loaded_entry : *loaded_entries)
entries.emplace_back(std::make_unique<TutorialGroup>(loaded_entry));
std::move(callback).Run(true, std::move(entries));
} }
} // namespace video_tutorials } // namespace video_tutorials
...@@ -47,7 +47,7 @@ class TutorialStore : public Store<TutorialGroup> { ...@@ -47,7 +47,7 @@ class TutorialStore : public Store<TutorialGroup> {
using EntryVector = std::vector<TutorialGroup>; using EntryVector = std::vector<TutorialGroup>;
// Store<TutorialGroup> implementation. // Store<TutorialGroup> implementation.
void InitAndLoadKeys(LoadKeysCallback callback) override; void Initialize(SuccessCallback callback) override;
void LoadEntries(const std::vector<std::string>& keys, void LoadEntries(const std::vector<std::string>& keys,
LoadEntriesCallback callback) override; LoadEntriesCallback callback) override;
void UpdateAll( void UpdateAll(
...@@ -56,20 +56,9 @@ class TutorialStore : public Store<TutorialGroup> { ...@@ -56,20 +56,9 @@ class TutorialStore : public Store<TutorialGroup> {
UpdateCallback callback) override; UpdateCallback callback) override;
// Called when db is initialized. // Called when db is initialized.
void OnDbInitialized(LoadKeysCallback callback, void OnDbInitialized(SuccessCallback callback,
leveldb_proto::Enums::InitStatus status); leveldb_proto::Enums::InitStatus status);
// Called when keys are loaded after initialization.
void OnKeysLoaded(LoadKeysCallback callback,
bool success,
std::unique_ptr<std::vector<std::string>> loaded_keys);
// Called when entries are loaded from db.
void OnEntriesLoaded(
LoadEntriesCallback callback,
bool success,
std::unique_ptr<std::vector<TutorialGroup>> loaded_entries);
TutorialProtoDb db_; TutorialProtoDb db_;
base::WeakPtrFactory<TutorialStore> weak_ptr_factory_{this}; base::WeakPtrFactory<TutorialStore> weak_ptr_factory_{this};
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "base/run_loop.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "chrome/browser/video_tutorials/test/test_utils.h" #include "chrome/browser/video_tutorials/test/test_utils.h"
#include "components/leveldb_proto/public/proto_database.h" #include "components/leveldb_proto/public/proto_database.h"
...@@ -26,46 +27,43 @@ class TutorialStoreTest : public testing::Test { ...@@ -26,46 +27,43 @@ class TutorialStoreTest : public testing::Test {
using EntriesMap = std::map<std::string, std::unique_ptr<TutorialGroup>>; using EntriesMap = std::map<std::string, std::unique_ptr<TutorialGroup>>;
using ProtoMap = std::map<std::string, TutorialGroupProto>; using ProtoMap = std::map<std::string, TutorialGroupProto>;
using KeysAndEntries = std::map<std::string, TutorialGroup>; using KeysAndEntries = std::map<std::string, TutorialGroup>;
using TestEntries = std::vector<TutorialGroup>;
using TestKeys = std::vector<std::string>;
TutorialStoreTest() : load_result_(false), db_(nullptr) {} TutorialStoreTest() : db_(nullptr) {}
~TutorialStoreTest() override = default; ~TutorialStoreTest() override = default;
TutorialStoreTest(const TutorialStoreTest& other) = delete; TutorialStoreTest(const TutorialStoreTest& other) = delete;
TutorialStoreTest& operator=(const TutorialStoreTest& other) = delete; TutorialStoreTest& operator=(const TutorialStoreTest& other) = delete;
protected: protected:
void Init(TestEntries input, InitStatus status) { void Init(std::vector<TutorialGroup> input,
InitStatus status,
bool expected_success) {
CreateTestDbEntries(std::move(input)); CreateTestDbEntries(std::move(input));
auto db = std::make_unique<FakeDB<TutorialGroupProto, TutorialGroup>>( auto db = std::make_unique<FakeDB<TutorialGroupProto, TutorialGroup>>(
&db_entries_); &db_entries_);
db_ = db.get(); db_ = db.get();
store_ = std::make_unique<TutorialStore>(std::move(db)); store_ = std::make_unique<TutorialStore>(std::move(db));
store_->InitAndLoadKeys(base::BindOnce(&TutorialStoreTest::OnKeysLoaded, store_->Initialize(base::BindOnce(&TutorialStoreTest::OnInitCompleted,
base::Unretained(this))); base::Unretained(this),
expected_success));
db_->InitStatusCallback(status); db_->InitStatusCallback(status);
} }
void OnKeysLoaded(bool success, void OnInitCompleted(bool expected_success, bool success) {
std::unique_ptr<std::vector<std::string>> loaded_keys) { EXPECT_EQ(expected_success, success);
load_result_ = success;
loaded_keys_.clear();
if (success && loaded_keys)
loaded_keys_ = *loaded_keys;
} }
void CreateTestDbEntries(TestEntries input) { void CreateTestDbEntries(std::vector<TutorialGroup> input) {
for (auto& entry : input) { for (auto& entry : input) {
TutorialGroupProto proto; TutorialGroupProto proto;
TutorialGroupToProto(&entry, &proto); TutorialGroupToProto(&entry, &proto);
db_entries_.emplace(entry.locale, proto); db_entries_.emplace(entry.language.locale, proto);
} }
} }
void VerifyLoadEntries(const TestKeys& keys, void LoadEntriesAndVerify(const std::vector<std::string>& keys,
bool expected_success, bool expected_success,
TestEntries expected_entries) { std::vector<TutorialGroup> expected_entries) {
store_->LoadEntries(keys, store_->LoadEntries(keys,
base::BindOnce(&TutorialStoreTest::OnEntriesLoaded, base::BindOnce(&TutorialStoreTest::OnEntriesLoaded,
base::Unretained(this), expected_success, base::Unretained(this), expected_success,
...@@ -75,14 +73,14 @@ class TutorialStoreTest : public testing::Test { ...@@ -75,14 +73,14 @@ class TutorialStoreTest : public testing::Test {
void OnEntriesLoaded( void OnEntriesLoaded(
bool expected_success, bool expected_success,
TestEntries expected_entries, std::vector<TutorialGroup> expected_entries,
bool success, bool success,
std::vector<std::unique_ptr<TutorialGroup>> loaded_entries) { std::unique_ptr<std::vector<TutorialGroup>> loaded_entries) {
EXPECT_EQ(expected_success, success); EXPECT_EQ(expected_success, success);
EXPECT_EQ(loaded_entries.size(), expected_entries.size()); EXPECT_EQ(loaded_entries->size(), expected_entries.size());
TestEntries actual_loaded_entries; std::vector<TutorialGroup> actual_loaded_entries;
for (auto& loaded_entry : loaded_entries) { for (auto& loaded_entry : *loaded_entries.get()) {
actual_loaded_entries.emplace_back(*loaded_entry.get()); actual_loaded_entries.emplace_back(loaded_entry);
} }
EXPECT_EQ(expected_entries, actual_loaded_entries); EXPECT_EQ(expected_entries, actual_loaded_entries);
} }
...@@ -109,18 +107,14 @@ class TutorialStoreTest : public testing::Test { ...@@ -109,18 +107,14 @@ class TutorialStoreTest : public testing::Test {
} }
} }
bool load_result() const { return load_result_; }
const EntriesMap& loaded_keys_and_entries() const { const EntriesMap& loaded_keys_and_entries() const {
return loaded_keys_and_entries_; return loaded_keys_and_entries_;
} }
const std::vector<std::string>& loaded_keys() const { return loaded_keys_; }
FakeDB<TutorialGroupProto, TutorialGroup>* db() { return db_; } FakeDB<TutorialGroupProto, TutorialGroup>* db() { return db_; }
Store<TutorialGroup>* store() { return store_.get(); } Store<TutorialGroup>* store() { return store_.get(); }
private: private:
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
bool load_result_{false};
TestKeys loaded_keys_;
EntriesMap loaded_keys_and_entries_; EntriesMap loaded_keys_and_entries_;
ProtoMap db_entries_; ProtoMap db_entries_;
FakeDB<TutorialGroupProto, TutorialGroup>* db_{nullptr}; FakeDB<TutorialGroupProto, TutorialGroup>* db_{nullptr};
...@@ -128,62 +122,63 @@ class TutorialStoreTest : public testing::Test { ...@@ -128,62 +122,63 @@ class TutorialStoreTest : public testing::Test {
}; };
// Test loading keys from a non-empty database in initialization successfully. // Test loading keys from a non-empty database in initialization successfully.
TEST_F(TutorialStoreTest, LoadedKeysSuccess) { TEST_F(TutorialStoreTest, InitSuccess) {
auto test_data = TestEntries();
TutorialGroup test_group; TutorialGroup test_group;
test::BuildTestGroup(&test_group); test::BuildTestGroup(&test_group);
std::string locale = test_group.locale; std::vector<TutorialGroup> test_data;
test_data.emplace_back(std::move(test_group)); test_data.emplace_back(std::move(test_group));
Init(std::move(test_data), InitStatus::kOK);
db()->LoadKeysCallback(true); Init(std::move(test_data), InitStatus::kOK, true /* expected */);
EXPECT_EQ(load_result(), true);
EXPECT_EQ(loaded_keys().size(), 1u);
EXPECT_EQ(loaded_keys().front(), locale);
} }
// Test loading keys from a non-empty database failed. // Test loading all entries from a non-empty database in initialization
TEST_F(TutorialStoreTest, LoadKeysFailed) { // successfully.
auto test_data = TestEntries(); TEST_F(TutorialStoreTest, LoadAllEntries) {
TutorialGroup test_group; TutorialGroup test_group;
test::BuildTestGroup(&test_group); test::BuildTestGroup(&test_group);
std::string locale = test_group.locale; std::vector<TutorialGroup> test_data;
test_data.emplace_back(std::move(test_group)); test_data.emplace_back(std::move(test_group));
Init(std::move(test_data), InitStatus::kOK); auto expected_test_data = test_data;
db()->LoadKeysCallback(false);
EXPECT_EQ(load_result(), false); Init(std::move(test_data), InitStatus::kOK, true /* expected */);
EXPECT_TRUE(loaded_keys().empty()); LoadEntriesAndVerify(std::vector<std::string>(), true, expected_test_data);
} }
// Test loading entries with loaded keys successfully. // Test loading keys from a non-empty database in initialization successfully.
TEST_F(TutorialStoreTest, LoadedEntriesSuccess) { TEST_F(TutorialStoreTest, LoadSpecificEntries) {
auto test_data = TestEntries();
TutorialGroup test_group; TutorialGroup test_group;
test::BuildTestGroup(&test_group); test::BuildTestGroup(&test_group);
std::string locale = test_group.locale; std::vector<TutorialGroup> test_data;
test_data.emplace_back(std::move(test_group)); test_data.emplace_back(std::move(test_group));
Init(test_data, InitStatus::kOK); auto expected_test_data = test_data;
db()->LoadKeysCallback(true);
EXPECT_EQ(load_result(), true); Init(std::move(test_data), InitStatus::kOK, true /* expected */);
EXPECT_EQ(loaded_keys().size(), 1u); std::vector<std::string> keys;
EXPECT_EQ(loaded_keys().front(), locale); keys.emplace_back("en");
LoadEntriesAndVerify(keys, true, expected_test_data);
VerifyLoadEntries(loaded_keys() /*keys*/, true /*expected_success*/, }
test_data /*expected_loaded_entries*/);
TEST_F(TutorialStoreTest, LoadEntryThatDoesntExist) {
std::vector<TutorialGroup> test_data;
auto expected_test_data = test_data;
Init(std::move(test_data), InitStatus::kOK, true /* expected */);
std::vector<std::string> keys;
keys.emplace_back("en");
LoadEntriesAndVerify(keys, true, expected_test_data);
} }
// Test adding and updating data successfully. // Test adding and updating data successfully.
TEST_F(TutorialStoreTest, AddAndUpdateDataSuccess) { TEST_F(TutorialStoreTest, AddAndUpdateDataSuccess) {
auto test_data = TestEntries(); std::vector<TutorialGroup> test_data;
Init(std::move(test_data), InitStatus::kOK); Init(std::move(test_data), InitStatus::kOK, true /* expected */);
db()->LoadKeysCallback(true);
EXPECT_EQ(load_result(), true);
EXPECT_TRUE(loaded_keys().empty());
// Add a group successfully. // Add a group successfully.
TutorialGroup test_group; TutorialGroup test_group;
test::BuildTestGroup(&test_group); test::BuildTestGroup(&test_group);
std::vector<std::pair<std::string, TutorialGroup>> entries_to_save; std::vector<std::pair<std::string, TutorialGroup>> entries_to_save;
entries_to_save.emplace_back(std::make_pair(test_group.locale, test_group)); entries_to_save.emplace_back(
std::make_pair(test_group.language.locale, test_group));
std::vector<std::string> keys_to_delete; std::vector<std::string> keys_to_delete;
store()->UpdateAll( store()->UpdateAll(
entries_to_save, keys_to_delete, entries_to_save, keys_to_delete,
...@@ -191,22 +186,19 @@ TEST_F(TutorialStoreTest, AddAndUpdateDataSuccess) { ...@@ -191,22 +186,19 @@ TEST_F(TutorialStoreTest, AddAndUpdateDataSuccess) {
db()->UpdateCallback(true); db()->UpdateCallback(true);
auto expected = std::make_unique<KeysAndEntries>(); auto expected = std::make_unique<KeysAndEntries>();
expected->emplace(test_group.locale, std::move(test_group)); expected->emplace(test_group.language.locale, std::move(test_group));
VerifyDataInDb(std::move(expected)); VerifyDataInDb(std::move(expected));
} }
// Test deleting entries with keys . // Test deleting entries with keys .
TEST_F(TutorialStoreTest, Delete) { TEST_F(TutorialStoreTest, Delete) {
auto test_data = TestEntries();
TutorialGroup test_group; TutorialGroup test_group;
test::BuildTestGroup(&test_group); test::BuildTestGroup(&test_group);
std::string locale = test_group.locale; std::string locale = test_group.language.locale;
std::vector<TutorialGroup> test_data;
test_data.emplace_back(std::move(test_group)); test_data.emplace_back(std::move(test_group));
Init(test_data, InitStatus::kOK); Init(test_data, InitStatus::kOK, true /* expected */);
db()->LoadKeysCallback(true);
EXPECT_EQ(load_result(), true);
EXPECT_EQ(loaded_keys().size(), 1u);
EXPECT_EQ(loaded_keys().front(), locale);
std::vector<std::string> keys{locale}; std::vector<std::string> keys{locale};
std::vector<std::pair<std::string, TutorialGroup>> entries_to_save; std::vector<std::pair<std::string, TutorialGroup>> entries_to_save;
......
...@@ -18,10 +18,22 @@ enum FeatureType { ...@@ -18,10 +18,22 @@ enum FeatureType {
TEST = 9999999; TEST = 9999999;
} }
// Metadata about a language.
message Language {
// The locale associated with the lnaguage.
string locale = 1;
// Name of the language.
string name = 2;
// Name of the language in native text.
string native_name = 3;
}
// A group of video tutorials with same language. // A group of video tutorials with same language.
message VideoTutorialGroup { message VideoTutorialGroup {
// Language of the video, in ISO-639-1 two character format. Eg: en, pl, hi. // Language of the video.
string locale = 1; Language language = 1;
// A list of video tutorials metadata. // A list of video tutorials metadata.
repeated VideoTutorial tutorials = 2; repeated VideoTutorial tutorials = 2;
......
...@@ -17,7 +17,9 @@ void BuildTestEntry(Tutorial* entry) { ...@@ -17,7 +17,9 @@ void BuildTestEntry(Tutorial* entry) {
} }
void BuildTestGroup(TutorialGroup* group) { void BuildTestGroup(TutorialGroup* group) {
*group = TutorialGroup("en"); Language language;
language.locale = "en";
*group = TutorialGroup(language);
group->tutorials.clear(); group->tutorials.clear();
Tutorial entry1; Tutorial entry1;
BuildTestEntry(&entry1); BuildTestEntry(&entry1);
......
...@@ -6,6 +6,15 @@ ...@@ -6,6 +6,15 @@
namespace video_tutorials { namespace video_tutorials {
bool Language::operator==(const Language& other) const {
return locale == other.locale && name == other.name &&
native_name == other.native_name;
}
bool Language::operator!=(const Language& other) const {
return !(*this == other);
}
Tutorial::Tutorial() : feature(FeatureType::kInvalid), video_length(0) {} Tutorial::Tutorial() : feature(FeatureType::kInvalid), video_length(0) {}
Tutorial::Tutorial(FeatureType feature, Tutorial::Tutorial(FeatureType feature,
......
...@@ -23,6 +23,27 @@ enum class FeatureType { ...@@ -23,6 +23,27 @@ enum class FeatureType {
kMaxValue = kSearch, kMaxValue = kSearch,
}; };
// In memory struct representing a language.
struct Language {
Language() = default;
~Language() = default;
Language(const Language& other) = default;
Language& operator=(const Language& other) = default;
bool operator==(const Language& other) const;
bool operator!=(const Language& other) const;
// The locale associated with the language.
std::string locale;
// The name of the language.
std::string name;
// The name of the language in native text.
std::string native_name;
};
// In memory struct of a video tutorial entry. // In memory struct of a video tutorial entry.
// Represents the metadata required to play a video tutorial. // Represents the metadata required to play a video tutorial.
struct Tutorial { struct Tutorial {
......
...@@ -33,7 +33,7 @@ class VideoTutorialService : public KeyedService, ...@@ -33,7 +33,7 @@ class VideoTutorialService : public KeyedService,
SingleItemCallback callback) = 0; SingleItemCallback callback) = 0;
// Called to retrieve all the supported locales. // Called to retrieve all the supported locales.
virtual std::vector<std::string> GetSupportedLocales() = 0; virtual const std::vector<Language>& GetSupportedLanguages() = 0;
// Called to retrieve the preferred locale. // Called to retrieve the preferred locale.
virtual std::string GetPreferredLocale() = 0; virtual std::string GetPreferredLocale() = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment