chromium/ios/chrome/browser/ui/reading_list/reading_list_app_interface.mm

// Copyright 2019 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/reading_list/reading_list_app_interface.h"

#import "base/location.h"
#import "base/memory/singleton.h"
#import "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "base/time/time.h"
#import "components/reading_list/core/reading_list_model.h"
#import "ios/chrome/browser/reading_list/model/reading_list_model_factory.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/app/tab_test_util.h"
#import "ios/testing/nserror_util.h"
#import "net/base/apple/url_conversions.h"
#import "net/base/network_change_notifier.h"

namespace {
// Returns the reading list model.
ReadingListModel* GetReadingListModel(NSError** error) {
  ReadingListModel* model =
      ReadingListModelFactory::GetInstance()->GetForBrowserState(
          chrome_test_util::GetOriginalBrowserState());
  if (!base::test::ios::WaitUntilConditionOrTimeout(base::Seconds(2), ^{
        return model->loaded();
      })) {
    *error = testing::NSErrorWithLocalizedDescription(
        @"Reading List model did not load");
  }
  return model;
}

// Overrides the NetworkChangeNotifier to enable distillation even if the device
// does not have network.
class WifiNetworkChangeNotifier : public net::NetworkChangeNotifier {
 public:
  WifiNetworkChangeNotifier() : net::NetworkChangeNotifier() {}

  WifiNetworkChangeNotifier(const WifiNetworkChangeNotifier&) = delete;
  WifiNetworkChangeNotifier& operator=(const WifiNetworkChangeNotifier&) =
      delete;

  ConnectionType GetCurrentConnectionType() const override {
    return CONNECTION_WIFI;
  }
};

// Overrides the NetworkChangeNotifier to enable distillation even if the device
// does not have network.
class ConnectionTypeOverrider {
 public:
  static ConnectionTypeOverrider* SharedInstance() {
    return base::Singleton<ConnectionTypeOverrider>::get();
  }

  ConnectionTypeOverrider() {}

  ConnectionTypeOverrider(const ConnectionTypeOverrider&) = delete;
  ConnectionTypeOverrider& operator=(const ConnectionTypeOverrider&) = delete;

  void OverrideConnectionType() {
    network_change_disabler_.reset(
        new net::NetworkChangeNotifier::DisableForTest());
    wifi_network_.reset(new WifiNetworkChangeNotifier());
  }

  void ResetConnectionType() {
    wifi_network_.reset();
    network_change_disabler_.reset();
  }

 private:
  std::unique_ptr<net::NetworkChangeNotifier::DisableForTest>
      network_change_disabler_;
  std::unique_ptr<WifiNetworkChangeNotifier> wifi_network_;
};

}  // namespace

@implementation ReadingListAppInterface

+ (NSError*)clearEntries {
  NSError* error = nil;
  ReadingListModel* model = GetReadingListModel(&error);
  if (error) {
    return error;
  }
  for (const GURL& url : model->GetKeys()) {
    model->RemoveEntryByURL(url, FROM_HERE);
  }
  return nil;
}

+ (NSError*)addEntryWithURL:(NSURL*)url title:(NSString*)title read:(BOOL)read {
  NSError* error = nil;
  ReadingListModel* model = GetReadingListModel(&error);
  if (error) {
    return error;
  }
  model->AddOrReplaceEntry(net::GURLWithNSURL(url),
                           base::SysNSStringToUTF8(title),
                           reading_list::ADDED_VIA_CURRENT_APP,
                           /*estimated_read_time=*/base::TimeDelta());
  if (read) {
    model->SetReadStatusIfExists(net::GURLWithNSURL(url), true);
  }
  return error;
}

+ (NSInteger)readEntriesCount {
  NSError* error = nil;
  ReadingListModel* model = GetReadingListModel(&error);
  if (error) {
    return -1;
  }
  return model->size() - model->unread_size();
}

+ (NSInteger)unreadEntriesCount {
  NSError* error = nil;
  ReadingListModel* model = GetReadingListModel(&error);
  if (error) {
    return -1;
  }
  return model->unread_size();
}

+ (void)forceConnectionToWifi {
  ConnectionTypeOverrider::SharedInstance()->OverrideConnectionType();
}

+ (void)notifyWifiConnection {
  if (net::NetworkChangeNotifier::IsOffline()) {
    net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
        net::NetworkChangeNotifier::CONNECTION_WIFI);
  }
}

+ (void)resetConnectionType {
  ConnectionTypeOverrider::SharedInstance()->ResetConnectionType();
}

@end