[go: nahoru, domu]

blob: 5bbf15ed9f63ea5d86b0e0ff17a0ec47b1419207 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/whats_new/data_source/whats_new_data_source.h"
#import "base/apple/bundle_locations.h"
#import "base/apple/foundation_util.h"
#import "base/notreached.h"
#import "base/strings/string_util.h"
#import "base/strings/sys_string_conversions.h"
#import "base/version.h"
#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
#import "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
#import "ios/chrome/browser/ui/whats_new/whats_new_util.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/grit/ios_chromium_strings.h"
#import "ios/chrome/grit/ios_google_chrome_strings.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util_mac.h"
#import "url/gurl.h"
namespace {
// The size of the icon image.
const CGFloat kIconImageWhatsNew = 16;
// The file name.
NSString* const kfileName = @"whats_new_entries.plist";
NSString* const kfileNameM116 = @"whats_new_entries_m116.plist";
// Dictionary keys.
NSString* const kDictionaryFeaturesKey = @"Features";
NSString* const kDictionaryChromeTipsKey = @"ChromeTips";
NSString* const kDictionaryTypeKey = @"Type";
NSString* const kDictionaryTitleKey = @"Title";
NSString* const kDictionarySubtitleKey = @"Subtitle";
NSString* const kDictionaryIsSymbolKey = @"IsSymbol";
NSString* const kDictionaryIsSystemSymbolKey = @"IsSystemSymbol";
NSString* const kDictionaryBannerImageKey = @"BannerImageName";
NSString* const kDictionaryImageNameKey = @"ImageName";
NSString* const kDictionaryImageTextKey = @"ImageTexts";
NSString* const kDictionaryHeroBannerImageKey = @"HeroBannerImageName";
NSString* const kDictionaryIconImageKey = @"IconImageName";
NSString* const kDictionaryBackgroundColorKey = @"IconBackgroundColor";
NSString* const kDictionaryInstructionsKey = @"InstructionSteps";
NSString* const kDictionaryPrimaryActionKey = @"PrimaryActionTitle";
NSString* const kDictionaryLearnMoreURLKey = @"LearnMoreUrlString";
// Returns the UIColor corresponding to `color`.
UIColor* GenerateColor(NSString* color) {
if ([color isEqualToString:@"blue"]) {
return [UIColor colorNamed:kBlue500Color];
} else if ([color isEqualToString:@"pink"]) {
return [UIColor colorNamed:kPink400Color];
} else if ([color isEqualToString:@"yellow"]) {
return [UIColor colorNamed:kYellow500Color];
} else if ([color isEqualToString:@"black"]) {
return [UIColor colorNamed:kGrey800Color];
} else if ([color isEqualToString:@"purple"]) {
return [UIColor colorNamed:kPurple500Color];
} else {
return nil;
}
}
// Returns a UIImage given an image name.
UIImage* GenerateImage(BOOL is_symbol, NSString* image, BOOL is_system_symbol) {
if (is_symbol) {
if (is_system_symbol) {
return DefaultSymbolTemplateWithPointSize(image, kIconImageWhatsNew);
}
return CustomSymbolTemplateWithPointSize(image, kIconImageWhatsNew);
}
return [UIImage imageNamed:image];
}
// Returns a localized string array given `instructions`.
NSArray<NSString*>* GenerateLocalizedInstructions(NSArray* instructions) {
NSMutableArray<NSString*>* localized_instructions =
[[NSMutableArray alloc] init];
for (NSObject* instruction in instructions) {
NSNumber* instruction_id = base::apple::ObjCCast<NSNumber>(instruction);
if (!instruction_id) {
return nil;
}
[localized_instructions
addObject:l10n_util::GetNSString([instruction_id intValue])];
}
return localized_instructions;
}
WhatsNewType WhatsNewTypeFromInt(int type) {
const int min_value = static_cast<int>(WhatsNewType::kMinValue);
const int max_value = static_cast<int>(WhatsNewType::kMaxValue);
if (min_value > type || type > max_value) {
NOTREACHED() << "unexpected type: " << type;
return WhatsNewType::kError;
}
return static_cast<WhatsNewType>(type);
}
NSArray<WhatsNewItem*>* WhatsNewItemsFromFileAndKey(NSString* path,
NSString* key) {
NSDictionary* entries = [NSDictionary dictionaryWithContentsOfFile:path];
NSMutableArray<WhatsNewItem*>* items = [[NSMutableArray alloc] init];
NSArray<NSObject*>* keys = entries[key];
if (!keys) {
return items;
}
for (NSObject* entry_key in keys) {
NSDictionary* entry = base::apple::ObjCCast<NSDictionary>(entry_key);
if (!entry) {
continue;
}
WhatsNewItem* item = ConstructWhatsNewItem(entry);
if (!item) {
continue;
}
[items addObject:item];
}
return items;
}
NSArray<NSString*>* loadInstructionsForPasswordInOtherApps(
NSArray<NSString*>* instructions) {
#if defined(__IPHONE_16_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_0
if (@available(iOS 16.0, *)) {
return @[
l10n_util::GetNSString(
IDS_IOS_WHATS_NEW_CHROME_TIP_PASSWORDS_IN_OTHER_APPS_STEP_1_IOS16),
l10n_util::GetNSString(
IDS_IOS_WHATS_NEW_CHROME_TIP_PASSWORDS_IN_OTHER_APPS_STEP_2_IOS16),
l10n_util::GetNSString(
IDS_IOS_WHATS_NEW_CHROME_TIP_PASSWORDS_IN_OTHER_APPS_STEP_2),
];
}
#endif // defined (__IPHONE_16_0)
return instructions;
}
} // namespace
NSArray<WhatsNewItem*>* WhatsNewFeatureEntries(NSString* path) {
return WhatsNewItemsFromFileAndKey(path, kDictionaryFeaturesKey);
}
NSArray<WhatsNewItem*>* WhatsNewChromeTipEntries(NSString* path) {
return WhatsNewItemsFromFileAndKey(path, kDictionaryChromeTipsKey);
}
WhatsNewItem* ConstructWhatsNewItem(NSDictionary* entry) {
// Load the entry type.
NSNumber* type_value =
base::apple::ObjCCast<NSNumber>(entry[kDictionaryTypeKey]);
if (!type_value) {
return nil;
}
WhatsNewType type = WhatsNewTypeFromInt([type_value intValue]);
// Do not create a WhatsNewItem with an inalid type.
if (type == WhatsNewType::kError) {
return nil;
}
WhatsNewItem* whats_new_item = [[WhatsNewItem alloc] init];
whats_new_item.type = type;
// Load the entry title.
NSNumber* title = base::apple::ObjCCast<NSNumber>(entry[kDictionaryTitleKey]);
if (!title) {
return nil;
}
whats_new_item.title = l10n_util::GetNSString([title intValue]);
// Load the entry subtitle.
NSNumber* subtitle =
base::apple::ObjCCast<NSNumber>(entry[kDictionarySubtitleKey]);
if (!subtitle) {
return nil;
}
whats_new_item.subtitle = l10n_util::GetNSString([subtitle intValue]);
// What's New M116 does not support hero banner or banner image.
if (!IsWhatsNewM116Enabled()) {
// Load the entry hero banner image.
NSString* hero_banner_image = entry[kDictionaryHeroBannerImageKey];
whats_new_item.heroBannerImage =
[hero_banner_image length] == 0
? nil
: GenerateImage(false, hero_banner_image, false);
// Load the entry banner image.
NSString* banner_image = entry[kDictionaryBannerImageKey];
whats_new_item.bannerImage =
[banner_image length] == 0 ? nil
: GenerateImage(false, banner_image, false);
}
// Load the entry icon.
BOOL is_symbol = [entry[kDictionaryIsSymbolKey] boolValue];
BOOL is_system_symbol = [entry[kDictionaryIsSystemSymbolKey] boolValue];
whats_new_item.iconImage = GenerateImage(
is_symbol, entry[kDictionaryIconImageKey], is_system_symbol);
// Load the entry icon background image.
whats_new_item.backgroundColor =
GenerateColor(entry[kDictionaryBackgroundColorKey]);
// Load the entry instructions.
NSArray<NSString*>* instructions =
GenerateLocalizedInstructions(entry[kDictionaryInstructionsKey]);
if (!instructions) {
return nil;
}
// Special case for kPasswordsInOtherApps, which has a different first step
// instruction on iOS 16.
if (whats_new_item.type == WhatsNewType::kPasswordsInOtherApps) {
whats_new_item.instructionSteps =
loadInstructionsForPasswordInOtherApps(instructions);
} else {
whats_new_item.instructionSteps = instructions;
}
// Load the entry primary action title.
NSNumber* primary_action_title =
base::apple::ObjCCast<NSNumber>(entry[kDictionaryPrimaryActionKey]);
if (!primary_action_title) {
whats_new_item.primaryActionTitle = nil;
} else {
whats_new_item.primaryActionTitle =
l10n_util::GetNSString([primary_action_title intValue]);
}
// Load the entry learn more url.
NSString* url = entry[kDictionaryLearnMoreURLKey];
if ([url length] > 0) {
GURL gurl(base::SysNSStringToUTF8(url));
[whats_new_item setLearnMoreURL:gurl];
} else {
[whats_new_item setLearnMoreURL:GURL::EmptyGURL()];
}
if (IsWhatsNewM116Enabled()) {
// Load screenshot image.
NSString* screenshot_image = entry[kDictionaryImageNameKey];
whats_new_item.screenshotName = screenshot_image;
// Load screenshot text provider.
NSDictionary* screenshot_texts = entry[kDictionaryImageTextKey];
NSMutableDictionary* screenshot_text_provider =
[NSMutableDictionary dictionaryWithCapacity:screenshot_texts.count];
for (id key in screenshot_texts) {
NSNumber* val =
base::apple::ObjCCast<NSNumber>([screenshot_texts objectForKey:key]);
[screenshot_text_provider setValue:l10n_util::GetNSString([val intValue])
forKey:key];
}
whats_new_item.screenshotTextProvider = screenshot_text_provider;
}
return whats_new_item;
}
NSString* WhatsNewFilePath() {
NSString* bundle_path = [base::apple::FrameworkBundle() bundlePath];
NSString* entries_file_path = [bundle_path
stringByAppendingPathComponent:IsWhatsNewM116Enabled() ? kfileNameM116
: kfileName];
return entries_file_path;
}