Compare commits
19 commits
master
...
alpha/2024
Author | SHA1 | Date | |
---|---|---|---|
b05cc564c6 | |||
2a3fc64a00 | |||
c77020d43d | |||
94e32b4b42 | |||
e6a4d0ff7a | |||
d28001d723 | |||
edf982ae7d | |||
69bc067ca9 | |||
aa63781b11 | |||
fcf985c2b1 | |||
48aac0a9eb | |||
2cbb5132dc | |||
92647d9691 | |||
0a573f3d69 | |||
eae5eac29c | |||
7a66304806 | |||
37b493e503 | |||
edef4d2e7f | |||
233334c4c9 |
|
@ -188,13 +188,23 @@ Java_app_organicmaps_editor_Editor_nativeShouldShowAddPlace(JNIEnv *, jclass)
|
|||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_app_organicmaps_editor_Editor_nativeShouldShowAddBusiness(JNIEnv *, jclass)
|
||||
Java_app_organicmaps_editor_Editor_nativeShouldEnableEditPlace(JNIEnv *, jclass)
|
||||
{
|
||||
::Framework * frm = g_framework->NativeFramework();
|
||||
if (!frm->HasPlacePageInfo())
|
||||
return static_cast<jboolean>(false);
|
||||
|
||||
return g_framework->GetPlacePageInfo().ShouldShowAddBusiness();
|
||||
return g_framework->GetPlacePageInfo().ShouldEnableEditPlace();
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_app_organicmaps_editor_Editor_nativeShouldEnableAddPlace(JNIEnv *, jclass)
|
||||
{
|
||||
::Framework * frm = g_framework->NativeFramework();
|
||||
if (!frm->HasPlacePageInfo())
|
||||
return static_cast<jboolean>(false);
|
||||
|
||||
return g_framework->GetPlacePageInfo().ShouldEnableAddPlace();
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
|
|
|
@ -55,7 +55,8 @@ public final class Editor
|
|||
|
||||
public static native boolean nativeShouldShowEditPlace();
|
||||
public static native boolean nativeShouldShowAddPlace();
|
||||
public static native boolean nativeShouldShowAddBusiness();
|
||||
public static native boolean nativeShouldEnableEditPlace();
|
||||
public static native boolean nativeShouldEnableAddPlace();
|
||||
@NonNull
|
||||
public static native int[] nativeGetEditableProperties();
|
||||
|
||||
|
|
|
@ -431,8 +431,9 @@ public class PlacePageView extends Fragment implements View.OnClickListener,
|
|||
else
|
||||
{
|
||||
UiUtils.showIf(Editor.nativeShouldShowEditPlace(), mEditPlace);
|
||||
UiUtils.showIf(Editor.nativeShouldShowAddBusiness(), mAddOrganisation);
|
||||
UiUtils.showIf(Editor.nativeShouldShowAddPlace(), mAddPlace);
|
||||
mEditPlace.setEnabled(Editor.nativeShouldEnableEditPlace());
|
||||
mAddPlace.setEnabled(Editor.nativeShouldEnableAddPlace());
|
||||
UiUtils.showIf(UiUtils.isVisible(mEditPlace)
|
||||
|| UiUtils.isVisible(mAddOrganisation)
|
||||
|| UiUtils.isVisible(mAddPlace), mEditTopSpace);
|
||||
|
|
|
@ -30537,6 +30537,98 @@
|
|||
zh-Hans = 备份
|
||||
zh-Hant = 备份
|
||||
|
||||
[icloud_synchronization_error_alert_title]
|
||||
comment = Title for the "iCloud synchronization failure" alert.
|
||||
tags = ios
|
||||
en = iCloud synchronization failure
|
||||
af = iCloud-sinchronisasie mislukking
|
||||
ar = فشل مزامنة iCloud
|
||||
az = iCloud sinxronizasiya uğursuzluğu
|
||||
be = Збой сінхранізацыі iCloud
|
||||
bg = Неуспешна синхронизация на iCloud
|
||||
ca = Error de sincronització d'iCloud
|
||||
cs = Selhání synchronizace iCloudu
|
||||
da = Fejl i iCloud-synkronisering
|
||||
de = iCloud-Synchronisierung fehlgeschlagen
|
||||
el = Αποτυχία συγχρονισμού iCloud
|
||||
es = Fallo de sincronización de iCloud
|
||||
et = iCloudi sünkroniseerimise tõrge
|
||||
eu = iCloud sinkronizazioaren hutsegitea
|
||||
fa = همگام سازی iCloud شکست خورده است
|
||||
fi = iCloud-synkronoinnin epäonnistuminen
|
||||
fr = Échec de la synchronisation iCloud
|
||||
he = כשל בסינכרון iCloud
|
||||
hi = iCloud सिंक्रनाइज़ेशन विफलता
|
||||
hu = iCloud-szinkronizálási hiba
|
||||
id = Kegagalan sinkronisasi iCloud
|
||||
it = Mancata sincronizzazione di iCloud
|
||||
ja = iCloud同期の失敗
|
||||
ko = iCloud 동기화 실패
|
||||
lt = "iCloud" sinchronizavimo sutrikimas
|
||||
mr = iCloud सिंक्रोनाइझेशन अयशस्वी
|
||||
nb = iCloud-synkroniseringsfeil
|
||||
nl = Storing iCloud-synchronisatie
|
||||
pl = Błąd synchronizacji iCloud
|
||||
pt = Falha de sincronização do iCloud
|
||||
pt-BR = Falha na sincronização do iCloud
|
||||
ro = Eșecul sincronizării iCloud
|
||||
ru = Сбой синхронизации iCloud
|
||||
sk = Zlyhanie synchronizácie iCloud
|
||||
sv = fel i iCloud-synkroniseringen
|
||||
sw = Imeshindwa kusawazisha iCloud
|
||||
th = การซิงโครไนซ์ iCloud ล้มเหลว
|
||||
tr = iCloud senkronizasyon hatası
|
||||
uk = Збій синхронізації iCloud
|
||||
vi = Lỗi đồng bộ hóa iCloud
|
||||
zh-Hans = iCloud 同步失败
|
||||
zh-Hant = iCloud 同步失敗
|
||||
|
||||
[icloud_synchronization_error_alert_message]
|
||||
comment = Message for the "iCloud synchronization failure" alert.
|
||||
tags = ios
|
||||
en = Would you like to send a bug report to the developers?
|
||||
af = Wil jy 'n foutverslag aan die ontwikkelaars stuur?
|
||||
ar = هل ترغب في إرسال تقرير عن الأخطاء إلى المطورين؟
|
||||
az = Tərtibatçılara səhv hesabatı göndərmək istərdinizmi?
|
||||
be = Хочаце адправіць справаздачу пра памылку распрацоўшчыкам?
|
||||
bg = Искате ли да изпратите доклад за грешка на разработчиците?
|
||||
ca = Voleu enviar un informe d'error als desenvolupadors?
|
||||
cs = Chcete poslat vývojářům hlášení o chybě?
|
||||
da = Vil du gerne sende en fejlrapport til udviklerne?
|
||||
de = Willst du einen Fehlerbericht an die Entwickler schicken?
|
||||
el = Θα θέλατε να στείλετε μια αναφορά σφάλματος στους προγραμματιστές;
|
||||
es = ¿Quieres enviar un informe de error a los desarrolladores?
|
||||
et = Kas soovite saata arendajatele veateate?
|
||||
eu = Akatsen txostena bidali nahi diezu garatzaileei?
|
||||
fa = آیا می خواهید یک گزارش اشکال برای توسعه دهندگان ارسال کنید؟
|
||||
fi = Haluatko lähettää vikailmoituksen kehittäjille?
|
||||
fr = Veux-tu envoyer un rapport de bogue aux développeurs ?
|
||||
he = האם תרצה לשלוח דוח באג למפתחים?
|
||||
hi = क्या आप डेवलपर्स को बग रिपोर्ट भेजना चाहेंगे?
|
||||
hu = Szeretne hibajelentést küldeni a fejlesztőknek?
|
||||
id = Apakah Anda ingin mengirim laporan bug ke pengembang?
|
||||
it = Vuoi inviare una segnalazione di bug agli sviluppatori?
|
||||
ja = 開発者にバグレポートを送りたいか?
|
||||
ko = 개발자에게 버그 리포트를 보내시겠습니까?
|
||||
lt = Ar norėtumėte išsiųsti pranešimą apie klaidą kūrėjams?
|
||||
mr = तुम्ही विकासकांना बग अहवाल पाठवू इच्छिता?
|
||||
nb = Vil du sende en feilrapport til utviklerne?
|
||||
nl = Wil je een bugrapport naar de ontwikkelaars sturen?
|
||||
pl = Chcesz wysłać raport o błędzie do deweloperów?
|
||||
pt = Gostarias de enviar um relatório de erro para os programadores?
|
||||
pt-BR = Você gostaria de enviar um relatório de bug para os desenvolvedores?
|
||||
ro = Doriți să trimiteți un raport de eroare dezvoltatorilor?
|
||||
ru = Хотите отправить разработчикам сообщение об ошибке?
|
||||
sk = Chcete poslať vývojárom hlásenie o chybe?
|
||||
sv = Vill du skicka en felrapport till utvecklarna?
|
||||
sw = Je, ungependa kutuma ripoti ya hitilafu kwa wasanidi programu?
|
||||
th = คุณต้องการส่งรายงานข้อผิดพลาดไปยังนักพัฒนาหรือไม่?
|
||||
tr = Geliştiricilere bir hata raporu göndermek ister misiniz?
|
||||
uk = Бажаєте надіслати розробникам звіт про помилку?
|
||||
vi = Bạn có muốn gửi báo cáo lỗi cho nhà phát triển không?
|
||||
zh-Hans = 您想向开发人员发送错误报告吗?
|
||||
zh-Hant = 您想向開發人員發送錯誤報告嗎?
|
||||
|
||||
[icloud_synchronization_error_connection_error]
|
||||
comment = iCloud error message: Failed to synchronize due to connection error
|
||||
tags = ios
|
||||
|
@ -30676,3 +30768,49 @@
|
|||
vi = Lỗi: iCloud không khả dụng
|
||||
zh-Hans = 错误:iCloud 不可用
|
||||
zh-Hant = 錯誤:iCloud 不可用
|
||||
|
||||
[open_in_app]
|
||||
comment = Title for the "Open In Another App" button on the PlacePage.
|
||||
tags = ios
|
||||
en = Open In Another App
|
||||
af = Maak oop in 'n ander toepassing
|
||||
ar = فتح في تطبيق آخر
|
||||
az = Başqa Tətbiqdə Açın
|
||||
be = Адкрыць у іншай прыладзе
|
||||
bg = Отваряне в друго приложение
|
||||
ca = Obre en una altra aplicació
|
||||
cs = Otevřít v jiné aplikaci
|
||||
da = Åbn i en anden app
|
||||
de = In einer anderen App öffnen
|
||||
el = Άνοιγμα σε άλλη εφαρμογή
|
||||
es = Abrir en otra aplicación
|
||||
et = Avatud teises rakenduses
|
||||
eu = Ireki beste aplikazio batean
|
||||
fa = در یک برنامه دیگر باز کنید
|
||||
fi = Avaa toisessa sovelluksessa
|
||||
fr = Ouvrir dans une autre application
|
||||
he = פתח באפליקציה אחרת
|
||||
hi = किसी अन्य ऐप में खोलें
|
||||
hu = Megnyitás egy másik alkalmazásban
|
||||
id = Buka di Aplikasi Lain
|
||||
it = Apri in un'altra applicazione
|
||||
ja = 別のアプリで開く
|
||||
ko = 다른 앱에서 열기
|
||||
lt = Atidaryti kitoje programoje
|
||||
mr = दुसऱ्या ॲपमध्ये उघडा
|
||||
nb = Åpne i en annen app
|
||||
nl = Openen in een andere app
|
||||
pl = Otwórz w innej aplikacji
|
||||
pt = Abrir noutra aplicação
|
||||
pt-BR = Abrir em outro aplicativo
|
||||
ro = Deschidere în altă aplicație
|
||||
ru = Открыть в другом приложении
|
||||
sk = Otvoriť v inej aplikácii
|
||||
sv = Öppna i en annan app
|
||||
sw = Fungua Katika Programu Nyingine
|
||||
th = เปิดในแอปอื่น
|
||||
tr = Başka Bir Uygulamada Aç
|
||||
uk = Відкрити в іншій програмі
|
||||
vi = Mở trong ứng dụng khác
|
||||
zh-Hans = 在另一个应用程序中打开
|
||||
zh-Hant = 在另一個應用程式中打開
|
||||
|
|
|
@ -166,6 +166,11 @@ void DrapeEngine::SetVisibleViewport(m2::RectD const & rect) const
|
|||
MessagePriority::Normal);
|
||||
}
|
||||
|
||||
int DrapeEngine::GetCurrentZoomLevel() const
|
||||
{
|
||||
return m_frontend->GetCurrentZoom();
|
||||
}
|
||||
|
||||
void DrapeEngine::Invalidate()
|
||||
{
|
||||
m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread,
|
||||
|
|
|
@ -119,6 +119,8 @@ public:
|
|||
|
||||
void SetVisibleViewport(m2::RectD const & rect) const;
|
||||
|
||||
int GetCurrentZoomLevel() const;
|
||||
|
||||
void AddTouchEvent(TouchEvent const & event);
|
||||
void Scale(double factor, m2::PointD const & pxPoint, bool isAnim);
|
||||
void Move(double factorX, double factorY, bool isAnim);
|
||||
|
|
|
@ -2524,6 +2524,12 @@ void FrontendRenderer::ChangeModelView(double autoScale, m2::PointD const & user
|
|||
AddUserEvent(make_unique_dp<FollowAndRotateEvent>(userPos, pxZero, azimuth, autoScale, parallelAnimCreator));
|
||||
}
|
||||
|
||||
int FrontendRenderer::GetCurrentZoom() const
|
||||
{
|
||||
ASSERT(IsValidCurrentZoom(), ());
|
||||
return m_currentZoomLevel;
|
||||
}
|
||||
|
||||
void FrontendRenderer::OnEnterBackground()
|
||||
{
|
||||
m_myPositionController->OnEnterBackground();
|
||||
|
|
|
@ -145,6 +145,7 @@ public:
|
|||
|
||||
drape_ptr<ScenarioManager> const & GetScenarioManager() const { return m_scenarioManager; }
|
||||
location::EMyPositionMode GetMyPositionMode() const { return m_myPositionController->GetCurrentMode(); }
|
||||
int GetCurrentZoom() const;
|
||||
|
||||
void OnEnterBackground();
|
||||
|
||||
|
@ -351,12 +352,6 @@ private:
|
|||
return m_currentZoomLevel >= 0;
|
||||
}
|
||||
|
||||
int GetCurrentZoom() const
|
||||
{
|
||||
ASSERT(IsValidCurrentZoom(), ());
|
||||
return m_currentZoomLevel;
|
||||
}
|
||||
|
||||
int m_currentZoomLevel = -1;
|
||||
|
||||
ref_ptr<RequestedTiles> m_requestedTiles;
|
||||
|
|
|
@ -18,6 +18,7 @@ NS_SWIFT_NAME(GeoUtil)
|
|||
@interface MWMGeoUtil : NSObject
|
||||
|
||||
+ (float)angleAtPoint:(CLLocationCoordinate2D)p1 toPoint:(CLLocationCoordinate2D)p2;
|
||||
+ (NSString *)formattedOsmLinkForCoordinate:(CLLocationCoordinate2D)coordinate zoomLevel:(int)zoomLevel;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#import "MWMGeoUtil.h"
|
||||
#import "MWMFrameworkHelper.h"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
#include "geometry/angles.hpp"
|
||||
|
@ -7,6 +8,7 @@
|
|||
#include "platform/localization.hpp"
|
||||
#include "platform/settings.hpp"
|
||||
#include "platform/measurement_utils.hpp"
|
||||
#include "drape_frontend/frontend_renderer.hpp"
|
||||
|
||||
@implementation Measure
|
||||
|
||||
|
@ -58,4 +60,9 @@
|
|||
return ang::AngleTo(mp1, mp2);
|
||||
}
|
||||
|
||||
+ (NSString *)formattedOsmLinkForCoordinate:(CLLocationCoordinate2D)coordinate zoomLevel:(int)zoomLevel {
|
||||
auto const link = measurement_utils::FormatOsmLink(coordinate.latitude, coordinate.longitude, zoomLevel);
|
||||
return [NSString stringWithCString:link.c_str() encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -34,12 +34,13 @@ NS_SWIFT_NAME(FrameworkHelper)
|
|||
+ (void)searchInDownloader:(NSString *)query
|
||||
inputLocale:(NSString *)locale
|
||||
completion:(SearchInDownloaderCompletions)completion;
|
||||
+ (BOOL)canEditMap;
|
||||
+ (BOOL)canEditMapAtViewportCenter;
|
||||
+ (void)showOnMap:(MWMMarkGroupID)categoryId;
|
||||
+ (void)showBookmark:(MWMMarkID)bookmarkId;
|
||||
+ (void)showTrack:(MWMTrackID)trackId;
|
||||
+ (void)updatePlacePageData;
|
||||
+ (void)updateAfterDeleteBookmark;
|
||||
+ (int)currentZoomLevel;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -162,8 +162,9 @@
|
|||
GetFramework().GetSearchAPI().SearchInDownloader(std::move(params));
|
||||
}
|
||||
|
||||
+ (BOOL)canEditMap {
|
||||
return GetFramework().CanEditMap();
|
||||
+ (BOOL)canEditMapAtViewportCenter {
|
||||
auto &f = GetFramework();
|
||||
return f.CanEditMapForPosition(f.GetViewportCenter());
|
||||
}
|
||||
|
||||
+ (void)showOnMap:(MWMMarkGroupID)categoryId {
|
||||
|
@ -190,4 +191,9 @@
|
|||
buildInfo.m_source = place_page::BuildInfo::Source::Other;
|
||||
frm.UpdatePlacePageInfoForCurrentSelection(buildInfo);
|
||||
}
|
||||
|
||||
+ (int)currentZoomLevel {
|
||||
return GetFramework().GetCurrentZoomLevel();
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -6,7 +6,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property(nonatomic, readonly) BOOL showAddPlace;
|
||||
@property(nonatomic, readonly) BOOL showEditPlace;
|
||||
@property(nonatomic, readonly) BOOL showAddBusiness;
|
||||
|
||||
@property(nonatomic, readonly) BOOL enableAddPlace;
|
||||
@property(nonatomic, readonly) BOOL enableEditPlace;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -11,8 +11,9 @@
|
|||
if (self) {
|
||||
_showAddPlace = rawData.ShouldShowAddPlace();
|
||||
_showEditPlace = rawData.ShouldShowEditPlace();
|
||||
_showAddBusiness = rawData.ShouldShowAddBusiness();
|
||||
if (_showAddPlace || _showEditPlace || _showAddBusiness)
|
||||
_enableAddPlace = rawData.ShouldEnableAddPlace();
|
||||
_enableEditPlace = rawData.ShouldEnableEditPlace();
|
||||
if (_showAddPlace || _showEditPlace || _enableAddPlace || _enableEditPlace)
|
||||
return self;
|
||||
}
|
||||
return nil;
|
||||
|
|
|
@ -246,7 +246,7 @@ extension BookmarksListViewController: IBookmarksListView {
|
|||
message: L("share_bookmarks_email_body")) { (_, _, _, _) in
|
||||
completion()
|
||||
}
|
||||
shareController?.present(inParentViewController: self, anchorView: self.toolBar)
|
||||
shareController.present(inParentViewController: self, anchorView: self.toolBar)
|
||||
}
|
||||
|
||||
func showError(title: String, message: String) {
|
||||
|
|
|
@ -87,7 +87,7 @@ final class BMCViewController: MWMViewController {
|
|||
{ [weak self] _, _, _, _ in
|
||||
self?.viewModel?.finishShareCategory()
|
||||
}
|
||||
shareController?.present(inParentViewController: self, anchorView: anchorView)
|
||||
shareController.present(inParentViewController: self, anchorView: anchorView)
|
||||
case .emptyCategory:
|
||||
MWMAlertViewController.activeAlert().presentInfoAlert(L("bookmarks_error_title_share_empty"),
|
||||
text: L("bookmarks_error_message_share_empty"))
|
||||
|
|
|
@ -148,9 +148,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
applyPosition:hasPoint
|
||||
position:point
|
||||
doneBlock:^{
|
||||
auto &f = GetFramework();
|
||||
|
||||
if (IsPointCoveredByDownloadedMaps(f.GetViewportCenter(), f.GetStorage(), f.GetCountryInfoGetter()))
|
||||
if ([MWMFrameworkHelper canEditMapAtViewportCenter])
|
||||
[ownerController performSegueWithIdentifier:kMapToCategorySelectorSegue sender:nil];
|
||||
else
|
||||
[ownerController.alertController presentIncorrectFeauturePositionAlert];
|
||||
|
|
|
@ -6,13 +6,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NS_SWIFT_NAME(ActivityViewController)
|
||||
@interface MWMActivityViewController : UIActivityViewController
|
||||
|
||||
+ (nullable instancetype)shareControllerForEditorViral;
|
||||
+ (instancetype)shareControllerForEditorViral;
|
||||
|
||||
+ (nullable instancetype)shareControllerForMyPosition:(CLLocationCoordinate2D)location;
|
||||
+ (instancetype)shareControllerForMyPosition:(CLLocationCoordinate2D)location;
|
||||
|
||||
+ (nullable instancetype)shareControllerForPlacePage:(PlacePageData *)data;
|
||||
+ (instancetype)shareControllerForPlacePage:(PlacePageData *)data;
|
||||
|
||||
+ (nullable instancetype)shareControllerForURL:(nullable NSURL *)url
|
||||
+ (instancetype)shareControllerForURL:(nullable NSURL *)url
|
||||
message:(NSString *)message
|
||||
completionHandler:(nullable UIActivityViewControllerCompletionWithItemsHandler)completionHandler;
|
||||
|
||||
|
|
|
@ -59,6 +59,8 @@ class DayColors: IColors {
|
|||
var outdoorColor = UIColor(red: 0.235, green: 0.549, blue: 0.235, alpha: 1)
|
||||
var lonelyPlanetLogoColor = UIColor(red: 0, green: 0.286, blue: 0.565, alpha: 1)
|
||||
var carplayPlaceholderBackground = UIColor(221, 221, 205, alpha100)
|
||||
var iconOpaqueGrayTint = UIColor(117, 117, 117, alpha100)
|
||||
var iconOpaqueGrayBackground = UIColor(231, 231, 231, alpha100)
|
||||
}
|
||||
|
||||
class NightColors: IColors {
|
||||
|
@ -122,4 +124,6 @@ class NightColors: IColors {
|
|||
var outdoorColor = UIColor(147, 191, 57, alpha100)
|
||||
var lonelyPlanetLogoColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.7)
|
||||
var carplayPlaceholderBackground = UIColor(50, 54, 58, alpha100)
|
||||
var iconOpaqueGrayTint = UIColor(197, 197, 197, alpha100)
|
||||
var iconOpaqueGrayBackground = UIColor(84, 86, 90, alpha100)
|
||||
}
|
||||
|
|
|
@ -69,4 +69,6 @@ let alpha100: CGFloat = 1.0
|
|||
var outdoorColor: UIColor { get }
|
||||
var lonelyPlanetLogoColor: UIColor { get }
|
||||
var carplayPlaceholderBackground: UIColor { get }
|
||||
var iconOpaqueGrayTint: UIColor { get }
|
||||
var iconOpaqueGrayBackground: UIColor { get }
|
||||
}
|
||||
|
|
|
@ -111,8 +111,9 @@ class PlacePageStyleSheet: IStyleSheet {
|
|||
s.clip = true
|
||||
}
|
||||
|
||||
theme.add(styleName: "PPCloseButton") { (s) -> (Void) in
|
||||
s.tintColor = colors.blackDividers
|
||||
theme.add(styleName: "PPHeaderCircleIcon") { (s) -> (Void) in
|
||||
s.tintColor = colors.iconOpaqueGrayTint
|
||||
s.backgroundColor = colors.iconOpaqueGrayBackground
|
||||
}
|
||||
|
||||
theme.add(styleName: "ChartView") { (s) -> (Void) in
|
||||
|
|
|
@ -18,11 +18,23 @@ private let kBookmarksDirectoryName = "bookmarks"
|
|||
private let kICloudSynchronizationDidChangeEnabledStateNotificationName = "iCloudSynchronizationDidChangeEnabledStateNotification"
|
||||
private let kUDDidFinishInitialCloudSynchronization = "kUDDidFinishInitialCloudSynchronization"
|
||||
|
||||
final class CloudStorageSynchronizationState: NSObject {
|
||||
let isAvailable: Bool
|
||||
let isOn: Bool
|
||||
let error: NSError?
|
||||
|
||||
init(isAvailable: Bool, isOn: Bool, error: NSError?) {
|
||||
self.isAvailable = isAvailable
|
||||
self.isOn = isOn
|
||||
self.error = error
|
||||
}
|
||||
}
|
||||
|
||||
@objc @objcMembers final class CloudStorageManager: NSObject {
|
||||
|
||||
fileprivate struct Observation {
|
||||
weak var observer: AnyObject?
|
||||
var onErrorCompletionHandler: ((NSError?) -> Void)?
|
||||
var onSynchronizationStateDidChangeHandler: ((CloudStorageSynchronizationState) -> Void)?
|
||||
}
|
||||
|
||||
let fileManager: FileManager
|
||||
|
@ -33,7 +45,7 @@ private let kUDDidFinishInitialCloudSynchronization = "kUDDidFinishInitialCloudS
|
|||
private let synchronizationStateManager: SynchronizationStateManager
|
||||
private var fileWriter: SynchronizationFileWriter?
|
||||
private var observers = [ObjectIdentifier: CloudStorageManager.Observation]()
|
||||
private var synchronizationError: SynchronizationError? {
|
||||
private var synchronizationError: Error? {
|
||||
didSet { notifyObserversOnSynchronizationError(synchronizationError) }
|
||||
}
|
||||
|
||||
|
@ -104,13 +116,11 @@ private extension CloudStorageManager {
|
|||
guard let self else { return }
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
self.stopSynchronization()
|
||||
self.processError(error)
|
||||
case .success(let cloudDirectoryUrl):
|
||||
self.localDirectoryMonitor.start { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
self.stopSynchronization()
|
||||
self.processError(error)
|
||||
case .success(let localDirectoryUrl):
|
||||
self.fileWriter = SynchronizationFileWriter(fileManager: self.fileManager,
|
||||
|
@ -124,13 +134,30 @@ private extension CloudStorageManager {
|
|||
}
|
||||
}
|
||||
|
||||
func stopSynchronization() {
|
||||
func stopSynchronization(withError error: Error? = nil) {
|
||||
LOG(.debug, "Stop synchronization")
|
||||
localDirectoryMonitor.stop()
|
||||
cloudDirectoryMonitor.stop()
|
||||
synchronizationError = nil
|
||||
fileWriter = nil
|
||||
synchronizationStateManager.resetState()
|
||||
if let error {
|
||||
settings.setICLoudSynchronizationEnabled(false)
|
||||
synchronizationError = error
|
||||
MWMAlertViewController.activeAlert().presentDefaultAlert(withTitle: L("icloud_synchronization_error_alert_title"),
|
||||
message: L("icloud_synchronization_error_alert_message"),
|
||||
rightButtonTitle: L("report_a_bug"),
|
||||
leftButtonTitle: L("cancel"),
|
||||
rightButtonAction: {
|
||||
UIApplication.shared.showLoadingOverlay {
|
||||
let logFileURL = Logger.getLogFileURL()
|
||||
UIApplication.shared.hideLoadingOverlay {
|
||||
MailComposer.default.sendEmailWith(header: "Organic Maps Bugreport",
|
||||
toRecipients: [AboutInfo.reportABug.link!],
|
||||
attachmentFileURL: logFileURL)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func pauseSynchronization() {
|
||||
|
@ -228,53 +255,60 @@ private extension CloudStorageManager {
|
|||
func writingResultHandler(for event: OutgoingEvent) -> WritingResultCompletionHandler {
|
||||
return { [weak self] result in
|
||||
guard let self else { return }
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success:
|
||||
// Mark that initial synchronization is finished.
|
||||
if case .didFinishInitialSynchronization = event {
|
||||
UserDefaults.standard.set(true, forKey: kUDDidFinishInitialCloudSynchronization)
|
||||
}
|
||||
case .reloadCategoriesAtURLs(let urls):
|
||||
urls.forEach { self.bookmarksManager.reloadCategory(atFilePath: $0.path) }
|
||||
case .deleteCategoriesAtURLs(let urls):
|
||||
urls.forEach { self.bookmarksManager.deleteCategory(atFilePath: $0.path) }
|
||||
case .failure(let error):
|
||||
self.processError(error)
|
||||
switch result {
|
||||
case .success:
|
||||
// Mark that initial synchronization is finished.
|
||||
if case .didFinishInitialSynchronization = event {
|
||||
UserDefaults.standard.set(true, forKey: kUDDidFinishInitialCloudSynchronization)
|
||||
}
|
||||
case .reloadCategoriesAtURLs(let urls):
|
||||
DispatchQueue.main.async {
|
||||
urls.forEach { self.bookmarksManager.reloadCategory(atFilePath: $0.path) }
|
||||
}
|
||||
case .deleteCategoriesAtURLs(let urls):
|
||||
DispatchQueue.main.async {
|
||||
urls.forEach { self.bookmarksManager.deleteCategory(atFilePath: $0.path) }
|
||||
}
|
||||
case .failure(let error):
|
||||
self.processError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Error handling
|
||||
func processError(_ error: Error) {
|
||||
if let synchronizationError = error as? SynchronizationError {
|
||||
LOG(.debug, "Synchronization error: \(error.localizedDescription)")
|
||||
switch synchronizationError {
|
||||
case .fileUnavailable: break
|
||||
case .fileNotUploadedDueToQuota: break
|
||||
case .ubiquityServerNotAvailable: break
|
||||
case .iCloudIsNotAvailable: fallthrough
|
||||
case .failedToOpenLocalDirectoryFileDescriptor: fallthrough
|
||||
case .failedToRetrieveLocalDirectoryContent: fallthrough
|
||||
case .containerNotFound:
|
||||
switch error {
|
||||
case let syncError as SynchronizationError:
|
||||
switch syncError {
|
||||
case .fileUnavailable,
|
||||
.fileNotUploadedDueToQuota,
|
||||
.ubiquityServerNotAvailable:
|
||||
LOG(.warning, "Synchronization Warning: \(syncError.localizedDescription)")
|
||||
synchronizationError = syncError
|
||||
case .iCloudIsNotAvailable:
|
||||
LOG(.warning, "Synchronization Warning: \(error.localizedDescription)")
|
||||
stopSynchronization()
|
||||
case .failedToOpenLocalDirectoryFileDescriptor,
|
||||
.failedToRetrieveLocalDirectoryContent,
|
||||
.containerNotFound,
|
||||
.failedToCreateMetadataItem,
|
||||
.failedToRetrieveMetadataQueryContent:
|
||||
LOG(.error, "Synchronization Error: \(error.localizedDescription)")
|
||||
stopSynchronization(withError: error)
|
||||
}
|
||||
self.synchronizationError = synchronizationError
|
||||
} else {
|
||||
// TODO: Handle non-synchronization errors
|
||||
LOG(.debug, "Non-synchronization error: \(error.localizedDescription)")
|
||||
default:
|
||||
LOG(.debug, "Non-synchronization Error: \(error.localizedDescription)")
|
||||
stopSynchronization(withError: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CloudStorageManger Observing
|
||||
extension CloudStorageManager {
|
||||
func addObserver(_ observer: AnyObject, onErrorCompletionHandler: @escaping (NSError?) -> Void) {
|
||||
func addObserver(_ observer: AnyObject, synchronizationStateDidChangeHandler: @escaping (CloudStorageSynchronizationState) -> Void) {
|
||||
let id = ObjectIdentifier(observer)
|
||||
observers[id] = Observation(observer: observer, onErrorCompletionHandler:onErrorCompletionHandler)
|
||||
// Notify the new observer immediately to handle initial state.
|
||||
observers[id]?.onErrorCompletionHandler?(synchronizationError as NSError?)
|
||||
observers[id] = Observation(observer: observer, onSynchronizationStateDidChangeHandler: synchronizationStateDidChangeHandler)
|
||||
notifyObserversOnSynchronizationError(synchronizationError)
|
||||
}
|
||||
|
||||
func removeObserver(_ observer: AnyObject) {
|
||||
|
@ -282,10 +316,13 @@ extension CloudStorageManager {
|
|||
observers.removeValue(forKey: id)
|
||||
}
|
||||
|
||||
private func notifyObserversOnSynchronizationError(_ error: SynchronizationError?) {
|
||||
self.observers.removeUnreachable().forEach { _, observable in
|
||||
private func notifyObserversOnSynchronizationError(_ error: Error?) {
|
||||
let state = CloudStorageSynchronizationState(isAvailable: cloudDirectoryMonitor.isCloudAvailable(),
|
||||
isOn: settings.iCLoudSynchronizationEnabled(),
|
||||
error: error as? NSError)
|
||||
observers.removeUnreachable().forEach { _, observable in
|
||||
DispatchQueue.main.async {
|
||||
observable.onErrorCompletionHandler?(error as NSError?)
|
||||
observable.onSynchronizationStateDidChangeHandler?(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,9 @@ final class DefaultLocalDirectoryMonitor: LocalDirectoryMonitor {
|
|||
self.fileManager = fileManager
|
||||
self.directory = directory
|
||||
self.fileType = fileType
|
||||
try fileManager.createDirectoryIfNeeded(at: directory)
|
||||
if !fileManager.fileExists(atPath: directory.path) {
|
||||
try fileManager.createDirectory(at: directory, withIntermediateDirectories: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
@ -143,31 +145,23 @@ final class DefaultLocalDirectoryMonitor: LocalDirectoryMonitor {
|
|||
dispatchSourceDebounceState = .started(source: source)
|
||||
|
||||
do {
|
||||
let files = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [], options: [.skipsHiddenFiles], fileExtension: fileType.fileExtension)
|
||||
let contents = files.compactMap { url in
|
||||
do {
|
||||
let metadataItem = try LocalMetadataItem(fileUrl: url)
|
||||
return metadataItem
|
||||
} catch {
|
||||
delegate?.didReceiveLocalMonitorError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
let contentMetadataItems = LocalContents(contents)
|
||||
let files = try fileManager
|
||||
.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.contentModificationDateKey], options: [.skipsHiddenFiles])
|
||||
.filter { $0.pathExtension == fileType.fileExtension }
|
||||
let contents: LocalContents = try files.map { try LocalMetadataItem(fileUrl: $0) }
|
||||
|
||||
if !didFinishGatheringIsCalled {
|
||||
didFinishGatheringIsCalled = true
|
||||
LOG(.debug, "LocalMonitor: didFinishGathering called.")
|
||||
LOG(.debug, "LocalMonitor: contentMetadataItems count: \(contentMetadataItems.count)")
|
||||
delegate?.didFinishGathering(contents: contentMetadataItems)
|
||||
LOG(.debug, "LocalMonitor: contentMetadataItems count: \(contents.count)")
|
||||
delegate?.didFinishGathering(contents: contents)
|
||||
} else {
|
||||
LOG(.debug, "LocalMonitor: didUpdate called.")
|
||||
LOG(.debug, "LocalMonitor: contentMetadataItems count: \(contentMetadataItems.count)")
|
||||
delegate?.didUpdate(contents: contentMetadataItems)
|
||||
LOG(.debug, "LocalMonitor: contentMetadataItems count: \(contents.count)")
|
||||
delegate?.didUpdate(contents: contents)
|
||||
}
|
||||
} catch {
|
||||
LOG(.debug, "\(error)")
|
||||
delegate?.didReceiveLocalMonitorError(SynchronizationError.failedToRetrieveLocalDirectoryContent)
|
||||
delegate?.didReceiveLocalMonitorError(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,15 +196,4 @@ private extension FileManager {
|
|||
}
|
||||
return dispatchSource
|
||||
}
|
||||
|
||||
func createDirectoryIfNeeded(at url: URL) throws {
|
||||
if !fileExists(atPath: url.path) {
|
||||
try createDirectory(at: url, withIntermediateDirectories: true)
|
||||
}
|
||||
}
|
||||
|
||||
func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions, fileExtension: String) throws -> [URL] {
|
||||
let files = try contentsOfDirectory(at: url, includingPropertiesForKeys: keys, options: options)
|
||||
return files.filter { $0.pathExtension == fileExtension }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,19 @@
|
|||
protocol MetadataItem: Equatable, Hashable {
|
||||
var fileName: String { get }
|
||||
var fileUrl: URL { get }
|
||||
var fileSize: Int { get }
|
||||
var contentType: String { get }
|
||||
var creationDate: TimeInterval { get }
|
||||
var lastModificationDate: TimeInterval { get }
|
||||
}
|
||||
|
||||
struct LocalMetadataItem: MetadataItem {
|
||||
let fileName: String
|
||||
let fileUrl: URL
|
||||
let fileSize: Int
|
||||
let contentType: String
|
||||
let creationDate: TimeInterval
|
||||
let lastModificationDate: TimeInterval
|
||||
}
|
||||
|
||||
struct CloudMetadataItem: MetadataItem {
|
||||
let fileName: String
|
||||
let fileUrl: URL
|
||||
let fileSize: Int
|
||||
let contentType: String
|
||||
var isDownloaded: Bool
|
||||
let creationDate: TimeInterval
|
||||
var lastModificationDate: TimeInterval
|
||||
var isRemoved: Bool
|
||||
let downloadingError: NSError?
|
||||
|
@ -31,36 +22,14 @@ struct CloudMetadataItem: MetadataItem {
|
|||
}
|
||||
|
||||
extension LocalMetadataItem {
|
||||
init(metadataItem: NSMetadataItem) throws {
|
||||
guard let fileName = metadataItem.value(forAttribute: NSMetadataItemFSNameKey) as? String,
|
||||
let fileUrl = metadataItem.value(forAttribute: NSMetadataItemURLKey) as? URL,
|
||||
let fileSize = metadataItem.value(forAttribute: NSMetadataItemFSSizeKey) as? Int,
|
||||
let contentType = metadataItem.value(forAttribute: NSMetadataItemContentTypeKey) as? String,
|
||||
let creationDate = (metadataItem.value(forAttribute: NSMetadataItemFSCreationDateKey) as? Date)?.timeIntervalSince1970.rounded(.down),
|
||||
let lastModificationDate = (metadataItem.value(forAttribute: NSMetadataItemFSContentChangeDateKey) as? Date)?.timeIntervalSince1970.rounded(.down) else {
|
||||
throw NSError(domain: "LocalMetadataItem", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to initialize LocalMetadataItem from NSMetadataItem"])
|
||||
}
|
||||
self.fileName = fileName
|
||||
self.fileUrl = fileUrl
|
||||
self.fileSize = fileSize
|
||||
self.contentType = contentType
|
||||
self.creationDate = creationDate
|
||||
self.lastModificationDate = lastModificationDate
|
||||
}
|
||||
|
||||
init(fileUrl: URL) throws {
|
||||
let resources = try fileUrl.resourceValues(forKeys: [.fileSizeKey, .typeIdentifierKey, .contentModificationDateKey, .creationDateKey])
|
||||
guard let fileSize = resources.fileSize,
|
||||
let contentType = resources.typeIdentifier,
|
||||
let creationDate = resources.creationDate?.timeIntervalSince1970.rounded(.down),
|
||||
let lastModificationDate = resources.contentModificationDate?.timeIntervalSince1970.rounded(.down) else {
|
||||
throw NSError(domain: "LocalMetadataItem", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to initialize LocalMetadataItem from URL"])
|
||||
let resources = try fileUrl.resourceValues(forKeys: [.contentModificationDateKey])
|
||||
guard let lastModificationDate = resources.contentModificationDate?.roundedTime else {
|
||||
LOG(.error, "Failed to initialize LocalMetadataItem from URL's resources: \(resources)")
|
||||
throw SynchronizationError.failedToCreateMetadataItem
|
||||
}
|
||||
self.fileName = fileUrl.lastPathComponent
|
||||
self.fileUrl = fileUrl
|
||||
self.fileSize = fileSize
|
||||
self.contentType = contentType
|
||||
self.creationDate = creationDate
|
||||
self.lastModificationDate = lastModificationDate
|
||||
}
|
||||
|
||||
|
@ -70,48 +39,44 @@ extension LocalMetadataItem {
|
|||
}
|
||||
|
||||
extension CloudMetadataItem {
|
||||
init(metadataItem: NSMetadataItem) throws {
|
||||
init(metadataItem: NSMetadataItem, isRemoved: Bool = false) throws {
|
||||
guard let fileName = metadataItem.value(forAttribute: NSMetadataItemFSNameKey) as? String,
|
||||
let fileUrl = metadataItem.value(forAttribute: NSMetadataItemURLKey) as? URL,
|
||||
let fileSize = metadataItem.value(forAttribute: NSMetadataItemFSSizeKey) as? Int,
|
||||
let contentType = metadataItem.value(forAttribute: NSMetadataItemContentTypeKey) as? String,
|
||||
let downloadStatus = metadataItem.value(forAttribute: NSMetadataUbiquitousItemDownloadingStatusKey) as? String,
|
||||
let creationDate = (metadataItem.value(forAttribute: NSMetadataItemFSCreationDateKey) as? Date)?.timeIntervalSince1970.rounded(.down),
|
||||
let lastModificationDate = (metadataItem.value(forAttribute: NSMetadataItemFSContentChangeDateKey) as? Date)?.timeIntervalSince1970.rounded(.down),
|
||||
let lastModificationDate = (metadataItem.value(forAttribute: NSMetadataItemFSContentChangeDateKey) as? Date)?.roundedTime,
|
||||
let hasUnresolvedConflicts = metadataItem.value(forAttribute: NSMetadataUbiquitousItemHasUnresolvedConflictsKey) as? Bool else {
|
||||
throw NSError(domain: "CloudMetadataItem", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to initialize CloudMetadataItem from NSMetadataItem"])
|
||||
let allAttributes = metadataItem.values(forAttributes: metadataItem.attributes)
|
||||
LOG(.error, "Failed to initialize CloudMetadataItem from NSMetadataItem: \(allAttributes.debugDescription)")
|
||||
throw SynchronizationError.failedToCreateMetadataItem
|
||||
}
|
||||
self.fileName = fileName
|
||||
self.fileUrl = fileUrl
|
||||
self.fileSize = fileSize
|
||||
self.contentType = contentType
|
||||
self.isDownloaded = downloadStatus == NSMetadataUbiquitousItemDownloadingStatusCurrent
|
||||
self.creationDate = creationDate
|
||||
self.lastModificationDate = lastModificationDate
|
||||
self.isRemoved = CloudMetadataItem.isInTrash(fileUrl)
|
||||
self.isRemoved = isRemoved || CloudMetadataItem.isInTrash(fileUrl)
|
||||
self.hasUnresolvedConflicts = hasUnresolvedConflicts
|
||||
self.downloadingError = metadataItem.value(forAttribute: NSMetadataUbiquitousItemDownloadingErrorKey) as? NSError
|
||||
self.uploadingError = metadataItem.value(forAttribute: NSMetadataUbiquitousItemUploadingErrorKey) as? NSError
|
||||
}
|
||||
|
||||
init(fileUrl: URL) throws {
|
||||
let resources = try fileUrl.resourceValues(forKeys: [.nameKey, .fileSizeKey, .typeIdentifierKey, .contentModificationDateKey, .creationDateKey, .ubiquitousItemDownloadingStatusKey, .ubiquitousItemHasUnresolvedConflictsKey, .ubiquitousItemDownloadingErrorKey, .ubiquitousItemUploadingErrorKey])
|
||||
guard let fileSize = resources.fileSize,
|
||||
let contentType = resources.typeIdentifier,
|
||||
let creationDate = resources.creationDate?.timeIntervalSince1970.rounded(.down),
|
||||
let downloadStatus = resources.ubiquitousItemDownloadingStatus,
|
||||
let lastModificationDate = resources.contentModificationDate?.timeIntervalSince1970.rounded(.down),
|
||||
init(fileUrl: URL, isRemoved: Bool = false) throws {
|
||||
let resources = try fileUrl.resourceValues(forKeys: [.nameKey,
|
||||
.contentModificationDateKey,
|
||||
.ubiquitousItemDownloadingStatusKey,
|
||||
.ubiquitousItemHasUnresolvedConflictsKey,
|
||||
.ubiquitousItemDownloadingErrorKey,
|
||||
.ubiquitousItemUploadingErrorKey])
|
||||
guard let downloadStatus = resources.ubiquitousItemDownloadingStatus,
|
||||
let lastModificationDate = resources.contentModificationDate?.roundedTime,
|
||||
let hasUnresolvedConflicts = resources.ubiquitousItemHasUnresolvedConflicts else {
|
||||
throw NSError(domain: "CloudMetadataItem", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to initialize CloudMetadataItem from NSMetadataItem"])
|
||||
LOG(.error, "Failed to initialize CloudMetadataItem from \(fileUrl) resources: \(resources.allValues)")
|
||||
throw SynchronizationError.failedToCreateMetadataItem
|
||||
}
|
||||
self.fileName = fileUrl.lastPathComponent
|
||||
self.fileUrl = fileUrl
|
||||
self.fileSize = fileSize
|
||||
self.contentType = contentType
|
||||
self.isDownloaded = downloadStatus.rawValue == NSMetadataUbiquitousItemDownloadingStatusCurrent
|
||||
self.creationDate = creationDate
|
||||
self.lastModificationDate = lastModificationDate
|
||||
self.isRemoved = CloudMetadataItem.isInTrash(fileUrl)
|
||||
self.isRemoved = isRemoved || CloudMetadataItem.isInTrash(fileUrl)
|
||||
self.hasUnresolvedConflicts = hasUnresolvedConflicts
|
||||
self.downloadingError = resources.ubiquitousItemDownloadingError
|
||||
self.uploadingError = resources.ubiquitousItemUploadingError
|
||||
|
@ -154,3 +119,9 @@ extension Array where Element == CloudMetadataItem {
|
|||
filter { $0.hasUnresolvedConflicts == hasUnresolvedConflicts }
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Date {
|
||||
var roundedTime: TimeInterval {
|
||||
timeIntervalSince1970.rounded(.down)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
case containerNotFound
|
||||
case failedToOpenLocalDirectoryFileDescriptor
|
||||
case failedToRetrieveLocalDirectoryContent
|
||||
case failedToCreateMetadataItem
|
||||
case failedToRetrieveMetadataQueryContent
|
||||
}
|
||||
|
||||
extension SynchronizationError: LocalizedError {
|
||||
|
@ -21,13 +23,17 @@ extension SynchronizationError: LocalizedError {
|
|||
return "Failed to open local directory file descriptor"
|
||||
case .failedToRetrieveLocalDirectoryContent:
|
||||
return "Failed to retrieve local directory content"
|
||||
case .failedToCreateMetadataItem:
|
||||
return "Failed to create metadata item."
|
||||
case .failedToRetrieveMetadataQueryContent:
|
||||
return "Failed to retrieve NSMetadataQuery content."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SynchronizationError {
|
||||
static func fromError(_ error: Error) -> SynchronizationError? {
|
||||
let nsError = error as NSError
|
||||
extension Error {
|
||||
var ubiquitousError: SynchronizationError? {
|
||||
let nsError = self as NSError
|
||||
switch nsError.code {
|
||||
// NSURLUbiquitousItemDownloadingErrorKey contains an error with this code when the item has not been uploaded to iCloud by the other devices yet
|
||||
case NSUbiquitousFileUnavailableError:
|
||||
|
|
|
@ -215,10 +215,10 @@ final class DefaultSynchronizationStateManager: SynchronizationStateManager {
|
|||
|
||||
private static func getItemsWithErrors(_ cloudContents: CloudContents) -> [SynchronizationError] {
|
||||
cloudContents.reduce(into: [SynchronizationError](), { partialResult, cloudItem in
|
||||
if let downloadingError = cloudItem.downloadingError, let synchronizationError = SynchronizationError.fromError(downloadingError) {
|
||||
if let downloadingError = cloudItem.downloadingError, let synchronizationError = downloadingError.ubiquitousError {
|
||||
partialResult.append(synchronizationError)
|
||||
}
|
||||
if let uploadingError = cloudItem.uploadingError, let synchronizationError = SynchronizationError.fromError(uploadingError) {
|
||||
if let uploadingError = cloudItem.uploadingError, let synchronizationError = uploadingError.ubiquitousError {
|
||||
partialResult.append(synchronizationError)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -141,65 +141,34 @@ class iCloudDocumentsDirectoryMonitor: NSObject, CloudDirectoryMonitor {
|
|||
return metadataQuery
|
||||
}
|
||||
|
||||
class func getContentsFromNotification(_ notification: Notification, _ onError: (Error) -> Void) -> CloudContents {
|
||||
class func getContentsFromNotification(_ notification: Notification) throws -> CloudContents {
|
||||
guard let metadataQuery = notification.object as? NSMetadataQuery,
|
||||
let metadataItems = metadataQuery.results as? [NSMetadataItem] else {
|
||||
return []
|
||||
throw SynchronizationError.failedToRetrieveMetadataQueryContent
|
||||
}
|
||||
|
||||
let cloudMetadataItems = CloudContents(metadataItems.compactMap { item in
|
||||
do {
|
||||
return try CloudMetadataItem(metadataItem: item)
|
||||
} catch {
|
||||
onError(error)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
return cloudMetadataItems
|
||||
return try metadataItems.map { try CloudMetadataItem(metadataItem: $0) }
|
||||
}
|
||||
|
||||
// There are no ways to retrieve the content of iCloud's .Trash directory on the macOS because it uses different file system and place trashed content in the /Users/<user_name>/.Trash which cannot be observed without access.
|
||||
// When we get a new notification and retrieve the metadata from the object the actual list of items in iOS contains both current and deleted files (which is in .Trash/ directory now) but on macOS we only have absence of the file. So there are no way to get list of deleted items on macOS on didFinishGathering state.
|
||||
// Due to didUpdate state we can get the list of deleted items on macOS from the userInfo property but cannot get their new url.
|
||||
class func getTrashContentsFromNotification(_ notification: Notification, _ onError: (Error) -> Void) -> CloudContents {
|
||||
guard let removedItems = notification.userInfo?[NSMetadataQueryUpdateRemovedItemsKey] as? [NSMetadataItem] else { return [] }
|
||||
return CloudContents(removedItems.compactMap { metadataItem in
|
||||
do {
|
||||
var item = try CloudMetadataItem(metadataItem: metadataItem)
|
||||
// on macOS deleted file will not be in the ./Trash directory, but it doesn't mean that it is not removed because it is placed in the NSMetadataQueryUpdateRemovedItems array.
|
||||
item.isRemoved = true
|
||||
return item
|
||||
} catch {
|
||||
onError(error)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
class func getTrashContentsFromNotification(_ notification: Notification) throws -> CloudContents {
|
||||
guard let removedItems = notification.userInfo?[NSMetadataQueryUpdateRemovedItemsKey] as? [NSMetadataItem] else {
|
||||
return []
|
||||
}
|
||||
return try removedItems.map { try CloudMetadataItem(metadataItem: $0, isRemoved: true) }
|
||||
}
|
||||
|
||||
class func getTrashedContentsFromTrashDirectory(fileManager: FileManager, ubiquitousDocumentsDirectory: URL?, onError: (Error) -> Void) -> CloudContents {
|
||||
class func getTrashedContentsFromTrashDirectory(fileManager: FileManager, ubiquitousDocumentsDirectory: URL) throws -> CloudContents {
|
||||
// There are no ways to retrieve the content of iCloud's .Trash directory on macOS.
|
||||
if #available(iOS 14.0, *), ProcessInfo.processInfo.isiOSAppOnMac {
|
||||
return []
|
||||
}
|
||||
// On iOS we can get the list of deleted items from the .Trash directory but only when iCloud is enabled.
|
||||
guard let ubiquitousDocumentsDirectory,
|
||||
let trashDirectoryUrl = try? fileManager.trashDirectoryUrl(for: ubiquitousDocumentsDirectory),
|
||||
let removedItems = try? fileManager.contentsOfDirectory(at: trashDirectoryUrl,
|
||||
includingPropertiesForKeys: [.isDirectoryKey],
|
||||
options: [.skipsPackageDescendants, .skipsSubdirectoryDescendants]) else {
|
||||
return []
|
||||
}
|
||||
let removedCloudMetadataItems = CloudContents(removedItems.compactMap { url in
|
||||
do {
|
||||
var item = try CloudMetadataItem(fileUrl: url)
|
||||
item.isRemoved = true
|
||||
return item
|
||||
} catch {
|
||||
onError(error)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
return removedCloudMetadataItems
|
||||
let trashDirectoryUrl = try fileManager.trashDirectoryUrl(for: ubiquitousDocumentsDirectory)
|
||||
let removedItems = try fileManager.contentsOfDirectory(at: trashDirectoryUrl,
|
||||
includingPropertiesForKeys: [.isDirectoryKey],
|
||||
options: [.skipsPackageDescendants, .skipsSubdirectoryDescendants])
|
||||
return try removedItems.map { try CloudMetadataItem(fileUrl: $0, isRemoved: true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,16 +205,18 @@ private extension iCloudDocumentsDirectoryMonitor {
|
|||
}
|
||||
|
||||
@objc func queryDidFinishGathering(_ notification: Notification) {
|
||||
guard isCloudAvailable() else { return }
|
||||
guard isCloudAvailable(), let ubiquitousDocumentsDirectory else { return }
|
||||
metadataQuery?.disableUpdates()
|
||||
LOG(.debug, "iCloudMonitor: Query did finish gathering")
|
||||
let contents = Self.getContentsFromNotification(notification, metadataQueryErrorHandler)
|
||||
let trashedContents = Self.getTrashedContentsFromTrashDirectory(fileManager: fileManager,
|
||||
ubiquitousDocumentsDirectory: ubiquitousDocumentsDirectory,
|
||||
onError: metadataQueryErrorHandler)
|
||||
LOG(.debug, "iCloudMonitor: Cloud contents count: \(contents.count)")
|
||||
LOG(.debug, "iCloudMonitor: Trashed contents count: \(trashedContents.count)")
|
||||
delegate?.didFinishGathering(contents: contents + trashedContents)
|
||||
do {
|
||||
let contents = try Self.getContentsFromNotification(notification)
|
||||
let trashedContents = try Self.getTrashedContentsFromTrashDirectory(fileManager: fileManager, ubiquitousDocumentsDirectory: ubiquitousDocumentsDirectory)
|
||||
LOG(.debug, "iCloudMonitor: Cloud contents count: \(contents.count)")
|
||||
LOG(.debug, "iCloudMonitor: Trashed contents count: \(trashedContents.count)")
|
||||
delegate?.didFinishGathering(contents: contents + trashedContents)
|
||||
} catch {
|
||||
delegate?.didReceiveCloudMonitorError(error)
|
||||
}
|
||||
metadataQuery?.enableUpdates()
|
||||
}
|
||||
|
||||
|
@ -253,17 +224,15 @@ private extension iCloudDocumentsDirectoryMonitor {
|
|||
guard isCloudAvailable() else { return }
|
||||
metadataQuery?.disableUpdates()
|
||||
LOG(.debug, "iCloudMonitor: Query did update")
|
||||
let contents = Self.getContentsFromNotification(notification, metadataQueryErrorHandler)
|
||||
let trashedContents = Self.getTrashContentsFromNotification(notification, metadataQueryErrorHandler)
|
||||
LOG(.debug, "iCloudMonitor: Cloud contents count: \(contents.count)")
|
||||
LOG(.debug, "iCloudMonitor: Trashed contents count: \(trashedContents.count)")
|
||||
delegate?.didUpdate(contents: contents + trashedContents)
|
||||
do {
|
||||
let contents = try Self.getContentsFromNotification(notification)
|
||||
let trashedContents = try Self.getTrashContentsFromNotification(notification)
|
||||
LOG(.debug, "iCloudMonitor: Cloud contents count: \(contents.count)")
|
||||
LOG(.debug, "iCloudMonitor: Trashed contents count: \(trashedContents.count)")
|
||||
delegate?.didUpdate(contents: contents + trashedContents)
|
||||
} catch {
|
||||
delegate?.didReceiveCloudMonitorError(error)
|
||||
}
|
||||
metadataQuery?.enableUpdates()
|
||||
}
|
||||
|
||||
private var metadataQueryErrorHandler: (Error) -> Void {
|
||||
{ [weak self] error in
|
||||
self?.delegate?.didReceiveCloudMonitorError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_nav_bar_close.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_nav_bar_close@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_nav_bar_close@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 391 B |
Before Width: | Height: | Size: 691 B |
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Vector.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Vector@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Vector@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 674 B |
Before Width: | Height: | Size: 1.1 KiB |
15
iphone/Maps/Images.xcassets/Place Page/ic_close.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_28px_circle_close.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
3
iphone/Maps/Images.xcassets/Place Page/ic_close.imageset/ic_28px_circle_close.svg
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="28" height="28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.049 8c-.305 0-.555.1-.752.297A1.018 1.018 0 0 0 8 9.049c0 .305.1.556.297.754L12.494 14l-4.197 4.197a1.022 1.022 0 0 0-.297.754c0 .305.1.555.297.752.197.197.447.297.752.297s.556-.1.754-.297L14 15.506l4.197 4.197c.198.197.45.297.754.297.305 0 .555-.1.752-.297.197-.197.297-.447.297-.752s-.1-.556-.297-.754L15.506 14l4.197-4.197c.197-.198.297-.45.297-.754 0-.305-.1-.555-.297-.752A1.018 1.018 0 0 0 18.951 8c-.305 0-.556.1-.754.297L14 12.494 9.803 8.297A1.022 1.022 0 0 0 9.049 8Z" style="fill:#000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 596 B |
15
iphone/Maps/Images.xcassets/Place Page/ic_open_in_app.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_open_in_app.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
4
iphone/Maps/Images.xcassets/Place Page/ic_open_in_app.imageset/ic_open_in_app.svg
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path style="fill:#f0f;stroke:#000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:fill markers stroke" d="M20 9V4m-5 0h5m-9 9 9-9"/>
|
||||
<path style="fill:none;fill-opacity:.5;stroke:#000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:fill markers stroke" d="M11 6H6a2 2 135 0 0-2 2v10a2 2 45 0 0 2 2h10a2 2 135 0 0 2-2v-5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 487 B |
|
@ -1,17 +1,8 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_wheelchair_white.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
"filename" : "ic_placepage_wheelchair.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<svg height="24" width="24" fill="#e8eaed" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="17" cy="5" r="2" fill="#000"/>
|
||||
<path d="M8.76 7c-.81 0-1.54.47-1.87 1.2l-.28.76c-.21.56.11 1.17.68 1.33.49.14 1-.11 1.2-.58l.3-.71H11l-1.83 4.1c-.6 1.33.39 2.9 1.85 2.9h4.843l-.84 3.783a1 1 0 1 0 1.954.434l1-4.5a1 1 0 0 0 .015-.34A2.004 2.004 0 0 0 16 13.5h-1.86l1.67-3.67C16.42 8.5 15.44 7 13.96 7Z" fill="#000"/>
|
||||
<path d="M8 22c-1.383 0-2.563-.488-3.537-1.462C3.487 19.562 3 18.383 3 17c0-1.15.358-2.175 1.075-3.075a4.996 4.996 0 0 1 2.75-1.775.948.948 0 0 1 .75.113.963.963 0 0 1 .45.612.948.948 0 0 1-.113.75.963.963 0 0 1-.612.45 2.937 2.937 0 0 0-1.662 1.063A2.934 2.934 0 0 0 5 17c0 .833.292 1.542.875 2.125A2.893 2.893 0 0 0 8 20c.683 0 1.292-.208 1.825-.625.533-.417.892-.95 1.075-1.6.083-.267.242-.47.475-.613a.879.879 0 0 1 .75-.087c.267.083.47.242.612.475.142.233.171.483.088.75a4.905 4.905 0 0 1-1.788 2.675A4.863 4.863 0 0 1 8 22Z" fill="#000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 964 B |
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="48" height="48" version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m30.327 12c-1.3184 0-2.388 1.0669-2.388 2.3851 0 1.3183 1.0696 2.388 2.388 2.388 1.3182 0 2.388-1.0696 2.388-2.388 0-1.3182-1.0697-2.3851-2.388-2.3851zm-8.1593 1.156c-0.36747-0.01946-0.73901 0.10069-1.0266 0.35721l-3.1895 2.8464c-0.5877 0.5242-0.63955 1.4261-0.1153 2.0138 0.52428 0.58766 1.4262 0.63968 2.0138 0.1153l2.419-2.1572 1.9969 1.1616-3.527 4.0164c-1.4633 0.23866-2.7803 0.91509-3.8139 1.8873l1.8422 1.8422c0.83304-0.75747 1.9408-1.2207 3.1529-1.2207 2.5851 0 4.6857 2.1033 4.6857 4.6887 0 1.212-0.46048 2.3198-1.2178 3.1529l1.8422 1.8422c1.2276-1.3049 1.98-3.0622 1.98-4.9952 0-1.1516-0.26712-2.2407-0.74253-3.2092l1.9239-0.10689-0.46688 5.7433c-0.06402 0.78493 0.52009 1.4716 1.3051 1.5357 0.03929 0.0034 0.07929 0.0057 0.11812 0.0057 0.73497 0 1.3597-0.56526 1.4204-1.3107l0.59909-7.3719c0.03354-0.41084-0.11182-0.81586-0.39939-1.1109-0.2877-0.2952-0.68894-0.45282-1.0997-0.43033l-4.9726 0.27845 2.7367-3.1164c0.38979-0.44394 0.50227-1.0351 0.35159-1.5639-0.07955-0.36233-0.30137-0.69222-0.63846-0.90283-0.01024-0.0075-6.5394-3.8027-6.5394-3.8027-0.19997-0.1161-0.41798-0.17665-0.63846-0.1884zm-5.9909 11.059c-0.97051 1.2386-1.5497 2.7961-1.5497 4.4918 0 4.0275 3.2654 7.293 7.293 7.293 1.6955 0 3.2532-0.57913 4.4918-1.5497l-1.862-1.8647c-0.75056 0.51051-1.6556 0.81004-2.6297 0.81004-2.5851 0-4.6887-2.1033-4.6887-4.6887 0-0.97429 0.29657-1.8792 0.80722-2.6297l-1.862-1.862z" fill="#fff" stroke-width=".92306"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
15
iphone/Maps/Images.xcassets/Place Page/ic_share.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_28px_circle_share.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
4
iphone/Maps/Images.xcassets/Place Page/ic_share.imageset/ic_28px_circle_share.svg
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="28" height="28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 10c-.55 0-1.02.196-1.412.588A1.925 1.925 0 0 0 7 12v8c0 .55.196 1.02.588 1.412C7.98 21.804 8.45 22 9 22h10c.55 0 1.02-.196 1.412-.588.392-.392.588-.862.588-1.412v-8c0-.55-.196-1.02-.588-1.412A1.925 1.925 0 0 0 19 10h-2a.968.968 0 0 0-.713.287A.968.968 0 0 0 16 11c0 .283.095.521.287.713.192.192.43.287.713.287h2v8H9v-8h2a.968.968 0 0 0 .713-.287A.968.968 0 0 0 12 11a.968.968 0 0 0-.287-.713A.968.968 0 0 0 11 10Z" style="fill:#000"/>
|
||||
<path d="M14 4.4c-.267 0-.5.1-.7.3l-2.6 2.6c-.2.2-.296.433-.288.7.008.267.104.5.287.7.2.2.435.303.701.312.267.008.5-.087.7-.287l.9-.9V15c0 .283.095.521.287.713.192.192.43.287.713.287a.968.968 0 0 0 .713-.287A.968.968 0 0 0 15 15V7.824l.875.875c.2.2.438.301.713.301.275 0 .513-.1.713-.3.183-.2.273-.437.273-.712a.931.931 0 0 0-.273-.687l-2.602-2.602A.956.956 0 0 0 14 4.4Z" style="fill:#000"/>
|
||||
</svg>
|
After Width: | Height: | Size: 927 B |
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "دعم";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "فشل مزامنة iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "هل ترغب في إرسال تقرير عن الأخطاء إلى المطورين؟";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "خطأ: فشل المزامنة بسبب خطأ في الاتصال";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "خطأ: iCloud غير متوفر";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "فتح في تطبيق آخر";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Yedəkləmə";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud sinxronizasiya uğursuzluğu";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Tərtibatçılara səhv hesabatı göndərmək istərdinizmi?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Xəta: Bağlantı xətası səbəbindən sinxronizasiya alınmadı";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Xəta: iCloud mövcud deyil";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Başqa Tətbiqdə Açın";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Рэзервовае капіраванне";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Збой сінхранізацыі iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Хочаце адправіць справаздачу пра памылку распрацоўшчыкам?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Памылка: не ўдалося сінхранізаваць з-за памылкі злучэння";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Памылка: iCloud недаступны";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Адкрыць у іншай прыладзе";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Резервно копие";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Неуспешна синхронизация на iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Искате ли да изпратите доклад за грешка на разработчиците?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Грешка: Не успя да се синхронизира поради грешка при свързването";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Грешка: iCloud не е наличен";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Отваряне в друго приложение";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Còpia de seguretat";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Error de sincronització d'iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Voleu enviar un informe d'error als desenvolupadors?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Error: no s'ha pogut sincronitzar a causa d'un error de connexió";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Error: iCloud no està disponible";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Obre en una altra aplicació";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Záloha";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Selhání synchronizace iCloudu";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Chcete poslat vývojářům hlášení o chybě?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Chyba: Nepodařilo se synchronizovat z důvodu chyby připojení";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Chyba: iCloud není k dispozici";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Otevřít v jiné aplikaci";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Sikkerhedskopiering";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Fejl i iCloud-synkronisering";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Vil du gerne sende en fejlrapport til udviklerne?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Fejl: Kunne ikke synkronisere på grund af forbindelsesfejl";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Fejl: iCloud er ikke tilgængelig";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Åbn i en anden app";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Sicherung";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud-Synchronisierung fehlgeschlagen";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Willst du einen Fehlerbericht an die Entwickler schicken?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Fehler: Synchronisierung aufgrund eines Verbindungsfehlers fehlgeschlagen";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Fehler: iCloud ist nicht verfügbar";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "In einer anderen App öffnen";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Δημιουργία αντιγράφων ασφαλείας";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Αποτυχία συγχρονισμού iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Θα θέλατε να στείλετε μια αναφορά σφάλματος στους προγραμματιστές;";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Σφάλμα: Αποτυχία συγχρονισμού λόγω σφάλματος σύνδεσης";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Σφάλμα: Το iCloud δεν είναι διαθέσιμο";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Άνοιγμα σε άλλη εφαρμογή";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Backup";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud synchronization failure";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Would you like to send a bug report to the developers?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Error: Failed to synchronize due to connection error";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Error: iCloud is not available";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Open In Another App";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Backup";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud synchronization failure";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Would you like to send a bug report to the developers?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Error: Failed to synchronize due to connection error";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Error: iCloud is not available";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Open In Another App";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Respaldo";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Fallo de sincronización de iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "¿Quieres enviar un informe de error a los desarrolladores?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Error: No se ha podido sincronizar debido a un error de conexión";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Error: iCloud no está disponible";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Abrir en otra aplicación";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Copia de seguridad";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Fallo de sincronización de iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "¿Quieres enviar un informe de error a los desarrolladores?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Error: No se ha podido sincronizar debido a un error de conexión";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Error: iCloud no está disponible";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Abrir en otra aplicación";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Varukoopia";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloudi sünkroniseerimise tõrge";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Kas soovite saata arendajatele veateate?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Viga: Sünkroniseerimine ebaõnnestus ühenduse vea tõttu.";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Viga: iCloud ei ole saadaval";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Avatud teises rakenduses";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Babeskopia";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud sinkronizazioaren hutsegitea";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Akatsen txostena bidali nahi diezu garatzaileei?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Errorea: Ezin izan da sinkronizatu konexio-errore baten ondorioz";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Errorea: iCloud ez dago erabilgarri";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Ireki beste aplikazio batean";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "پشتیبان گیری";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "همگام سازی iCloud شکست خورده است";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "آیا می خواهید یک گزارش اشکال برای توسعه دهندگان ارسال کنید؟";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "خطا: به دلیل خطای اتصال همگام سازی نشد";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "خطا: iCloud در دسترس نیست";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "در یک برنامه دیگر باز کنید";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Varmuuskopiointi";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud-synkronoinnin epäonnistuminen";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Haluatko lähettää vikailmoituksen kehittäjille?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Virhe: Synkronointi epäonnistui yhteysvirheen vuoksi.";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Virhe: iCloud ei ole käytettävissä";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Avaa toisessa sovelluksessa";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Sauvegarde";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Échec de la synchronisation iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Veux-tu envoyer un rapport de bogue aux développeurs ?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Erreur : La synchronisation a échoué en raison d'une erreur de connexion";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Erreur : iCloud n'est pas disponible";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Ouvrir dans une autre application";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "גיבוי";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "כשל בסינכרון iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "האם תרצה לשלוח דוח באג למפתחים?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "שגיאה: הסנכרון נכשל עקב שגיאת חיבור";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "שגיאה: iCloud אינו זמין";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "פתח באפליקציה אחרת";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "बैकअप";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud सिंक्रनाइज़ेशन विफलता";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "क्या आप डेवलपर्स को बग रिपोर्ट भेजना चाहेंगे?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "त्रुटि: कनेक्शन त्रुटि के कारण सिंक्रनाइज़ करने में विफल";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "त्रुटि: iCloud उपलब्ध नहीं है";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "किसी अन्य ऐप में खोलें";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Biztonsági mentés";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud-szinkronizálási hiba";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Szeretne hibajelentést küldeni a fejlesztőknek?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Hiba: A szinkronizálás sikertelen volt a kapcsolat hibája miatt.";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Hiba: Az iCloud nem elérhető";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Megnyitás egy másik alkalmazásban";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Cadangan";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Kegagalan sinkronisasi iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Apakah Anda ingin mengirim laporan bug ke pengembang?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Kesalahan: Gagal menyinkronkan karena kesalahan koneksi";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Kesalahan: iCloud tidak tersedia";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Buka di Aplikasi Lain";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Backup";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Mancata sincronizzazione di iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Vuoi inviare una segnalazione di bug agli sviluppatori?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Errore: Impossibile sincronizzare a causa di un errore di connessione";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Errore: iCloud non è disponibile";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Apri in un'altra applicazione";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "バックアップ";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud同期の失敗";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "開発者にバグレポートを送りたいか?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "エラー:接続エラーにより同期に失敗した";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "エラー:iCloudが利用できない";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "別のアプリで開く";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "백업";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud 동기화 실패";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "개발자에게 버그 리포트를 보내시겠습니까?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "오류입니다: 연결 오류로 인해 동기화하지 못했습니다.";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "오류: iCloud를 사용할 수 없습니다.";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "다른 앱에서 열기";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "बॅकअप";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud सिंक्रोनाइझेशन अयशस्वी";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "तुम्ही विकासकांना बग अहवाल पाठवू इच्छिता?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "त्रुटी: कनेक्शन त्रुटीमुळे सिंक्रोनाइझ करण्यात अयशस्वी";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "त्रुटी: iCloud उपलब्ध नाही";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "दुसऱ्या ॲपमध्ये उघडा";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Sikkerhetskopiering";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud-synkroniseringsfeil";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Vil du sende en feilrapport til utviklerne?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Feil: Kunne ikke synkronisere på grunn av tilkoblingsfeil";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Feil: iCloud er ikke tilgjengelig";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Åpne i en annen app";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Back-up";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Storing iCloud-synchronisatie";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Wil je een bugrapport naar de ontwikkelaars sturen?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Fout: Synchronisatie mislukt door verbindingsfout";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Fout: iCloud is niet beschikbaar";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Openen in een andere app";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Kopia zapasowa";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Błąd synchronizacji iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Chcesz wysłać raport o błędzie do deweloperów?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Błąd: Nie udało się zsynchronizować z powodu błędu połączenia";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Błąd: usługa iCloud jest niedostępna";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Otwórz w innej aplikacji";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Backup";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Falha na sincronização do iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Você gostaria de enviar um relatório de bug para os desenvolvedores?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Erro: Falha na sincronização devido a erro de conexão";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Erro: o iCloud não está disponível";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Abrir em outro aplicativo";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Cópia de segurança";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Falha de sincronização do iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Gostarias de enviar um relatório de erro para os programadores?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Erro: Falha na sincronização devido a um erro de ligação";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Erro: o iCloud não está disponível";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Abrir noutra aplicação";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Backup";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Eșecul sincronizării iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Doriți să trimiteți un raport de eroare dezvoltatorilor?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Eroare: Nu s-a reușit sincronizarea din cauza unei erori de conexiune";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Eroare: iCloud nu este disponibil";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Deschidere în altă aplicație";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Резервная копия";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Сбой синхронизации iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Хотите отправить разработчикам сообщение об ошибке?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Ошибка: Не удалось выполнить синхронизацию из-за ошибки подключения";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Ошибка: iCloud недоступен";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Открыть в другом приложении";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Zálohovanie";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Zlyhanie synchronizácie iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Chcete poslať vývojárom hlásenie o chybe?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Chyba: Nepodarilo sa synchronizovať z dôvodu chyby pripojenia";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Chyba: iCloud nie je k dispozícii";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Otvoriť v inej aplikácii";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Säkerhetskopiering";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "fel i iCloud-synkroniseringen";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Vill du skicka en felrapport till utvecklarna?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Fel: Synkronisering misslyckades på grund av anslutningsfel";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Fel: iCloud är inte tillgängligt";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Öppna i en annan app";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Hifadhi nakala";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Imeshindwa kusawazisha iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Je, ungependa kutuma ripoti ya hitilafu kwa wasanidi programu?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Hitilafu: Imeshindwa kusawazisha kwa sababu ya hitilafu ya muunganisho";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Hitilafu: iCloud haipatikani";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Fungua Katika Programu Nyingine";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "สำรองข้อมูล";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "การซิงโครไนซ์ iCloud ล้มเหลว";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "คุณต้องการส่งรายงานข้อผิดพลาดไปยังนักพัฒนาหรือไม่?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "ข้อผิดพลาด: ไม่สามารถซิงโครไนซ์ได้เนื่องจากข้อผิดพลาดในการเชื่อมต่อ";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "ข้อผิดพลาด: iCloud ไม่พร้อมใช้งาน";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "เปิดในแอปอื่น";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Yedekle";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud senkronizasyon hatası";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Geliştiricilere bir hata raporu göndermek ister misiniz?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Hata oluştu: Bağlantı hatası nedeniyle senkronizasyon başarısız oldu";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Hata: iCloud kullanılamıyor";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Başka Bir Uygulamada Aç";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Резервне копіювання";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Збій синхронізації iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Бажаєте надіслати розробникам звіт про помилку?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Помилка: Не вдалося синхронізувати через помилку з'єднання";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Помилка: iCloud недоступний";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Відкрити в іншій програмі";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "Hỗ trợ";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "Lỗi đồng bộ hóa iCloud";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "Bạn có muốn gửi báo cáo lỗi cho nhà phát triển không?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "Lỗi: Không đồng bộ được do lỗi kết nối";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "Lỗi: iCloud không khả dụng";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "Mở trong ứng dụng khác";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "备份";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud 同步失败";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "您想向开发人员发送错误报告吗?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "错误:由于连接错误,同步失败";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "错误:iCloud 不可用";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "在另一个应用程序中打开";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -1353,6 +1353,12 @@
|
|||
/* Title for the "Enable iCloud Syncronization" alert's "Backup" action button. */
|
||||
"backup" = "备份";
|
||||
|
||||
/* Title for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_title" = "iCloud 同步失敗";
|
||||
|
||||
/* Message for the "iCloud synchronization failure" alert. */
|
||||
"icloud_synchronization_error_alert_message" = "您想向開發人員發送錯誤報告嗎?";
|
||||
|
||||
/* iCloud error message: Failed to synchronize due to connection error */
|
||||
"icloud_synchronization_error_connection_error" = "錯誤:由於連線錯誤而無法同步";
|
||||
|
||||
|
@ -1362,6 +1368,9 @@
|
|||
/* iCloud error message: iCloud is not available */
|
||||
"icloud_synchronization_error_cloud_is_unavailable" = "錯誤:iCloud 不可用";
|
||||
|
||||
/* Title for the "Open In Another App" buton on the PlacePage. */
|
||||
"open_in_app" = "在另一個應用程式中打開";
|
||||
|
||||
|
||||
/********** Types **********/
|
||||
|
||||
|
|
|
@ -475,6 +475,7 @@
|
|||
ED3EAC202B03C88100220A4A /* BottomTabBarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED3EAC1F2B03C88100220A4A /* BottomTabBarButton.swift */; };
|
||||
ED43B8BD2C12063500D07BAA /* DocumentPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED43B8BC2C12063500D07BAA /* DocumentPicker.swift */; };
|
||||
ED63CEB92BDF8F9D006155C4 /* SettingsTableViewiCloudSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED63CEB62BDF8F9C006155C4 /* SettingsTableViewiCloudSwitchCell.swift */; };
|
||||
ED77556E2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED77556D2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift */; };
|
||||
ED79A5AB2BD7AA9C00952D1F /* LoadingOverlayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5AA2BD7AA9C00952D1F /* LoadingOverlayViewController.swift */; };
|
||||
ED79A5AD2BD7BA0F00952D1F /* UIApplication+LoadingOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5AC2BD7BA0F00952D1F /* UIApplication+LoadingOverlay.swift */; };
|
||||
ED79A5D32BDF8D6100952D1F /* CloudStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5CB2BDF8D6100952D1F /* CloudStorageManager.swift */; };
|
||||
|
@ -484,7 +485,9 @@
|
|||
ED79A5D72BDF8D6100952D1F /* SynchronizationStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5CF2BDF8D6100952D1F /* SynchronizationStateManager.swift */; };
|
||||
ED79A5D82BDF8D6100952D1F /* DefaultLocalDirectoryMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5D02BDF8D6100952D1F /* DefaultLocalDirectoryMonitor.swift */; };
|
||||
ED7CCC4F2C1362E300E2A737 /* FileType.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7CCC4E2C1362E300E2A737 /* FileType.swift */; };
|
||||
ED808D0F2C38407800D52585 /* CircleImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED808D0E2C38407800D52585 /* CircleImageButton.swift */; };
|
||||
ED8270F02C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8270EF2C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift */; };
|
||||
ED9857082C4ED02D00694F6C /* MailComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED9857072C4ED02D00694F6C /* MailComposer.swift */; };
|
||||
ED9966802B94FBC20083CE55 /* ColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED99667D2B94FBC20083CE55 /* ColorPicker.swift */; };
|
||||
EDBD68072B625724005DD151 /* LocationServicesDisabledAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = EDBD68062B625724005DD151 /* LocationServicesDisabledAlert.xib */; };
|
||||
EDBD680B2B62572E005DD151 /* LocationServicesDisabledAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDBD680A2B62572E005DD151 /* LocationServicesDisabledAlert.swift */; };
|
||||
|
@ -492,6 +495,7 @@
|
|||
EDE243DD2B6D2E640057369B /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE243D52B6CF3980057369B /* AboutController.swift */; };
|
||||
EDE243E52B6D3F400057369B /* OSMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE243E42B6D3F400057369B /* OSMView.swift */; };
|
||||
EDE243E72B6D55610057369B /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE243E02B6D3EA00057369B /* InfoView.swift */; };
|
||||
EDE8EAEB2C2DBB99002777F5 /* OpenInApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE8EAEA2C2DBB99002777F5 /* OpenInApplication.swift */; };
|
||||
EDF838842C00B640007E4E67 /* SynchronizationFileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF838812C00B640007E4E67 /* SynchronizationFileWriter.swift */; };
|
||||
EDF838BE2C00B9D0007E4E67 /* LocalDirectoryMonitorDelegateMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF838AD2C00B9C7007E4E67 /* LocalDirectoryMonitorDelegateMock.swift */; };
|
||||
EDF838BF2C00B9D0007E4E67 /* SynchronizationStateManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDF838AF2C00B9C7007E4E67 /* SynchronizationStateManagerTests.swift */; };
|
||||
|
@ -1391,6 +1395,7 @@
|
|||
ED48BBB817C2B1E2003E7E92 /* CircleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleView.h; sourceTree = "<group>"; };
|
||||
ED48BBB917C2B1E2003E7E92 /* CircleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleView.m; sourceTree = "<group>"; };
|
||||
ED63CEB62BDF8F9C006155C4 /* SettingsTableViewiCloudSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewiCloudSwitchCell.swift; sourceTree = "<group>"; };
|
||||
ED77556D2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+openInAppActionSheet.swift"; sourceTree = "<group>"; };
|
||||
ED79A5AA2BD7AA9C00952D1F /* LoadingOverlayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingOverlayViewController.swift; sourceTree = "<group>"; };
|
||||
ED79A5AC2BD7BA0F00952D1F /* UIApplication+LoadingOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+LoadingOverlay.swift"; sourceTree = "<group>"; };
|
||||
ED79A5CB2BDF8D6100952D1F /* CloudStorageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudStorageManager.swift; sourceTree = "<group>"; };
|
||||
|
@ -1400,7 +1405,9 @@
|
|||
ED79A5CF2BDF8D6100952D1F /* SynchronizationStateManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizationStateManager.swift; sourceTree = "<group>"; };
|
||||
ED79A5D02BDF8D6100952D1F /* DefaultLocalDirectoryMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultLocalDirectoryMonitor.swift; sourceTree = "<group>"; };
|
||||
ED7CCC4E2C1362E300E2A737 /* FileType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileType.swift; sourceTree = "<group>"; };
|
||||
ED808D0E2C38407800D52585 /* CircleImageButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleImageButton.swift; sourceTree = "<group>"; };
|
||||
ED8270EF2C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewDetailedSwitchCell.swift; sourceTree = "<group>"; };
|
||||
ED9857072C4ED02D00694F6C /* MailComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposer.swift; sourceTree = "<group>"; };
|
||||
ED99667D2B94FBC20083CE55 /* ColorPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPicker.swift; sourceTree = "<group>"; };
|
||||
EDBD68062B625724005DD151 /* LocationServicesDisabledAlert.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LocationServicesDisabledAlert.xib; sourceTree = "<group>"; };
|
||||
EDBD680A2B62572E005DD151 /* LocationServicesDisabledAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationServicesDisabledAlert.swift; sourceTree = "<group>"; };
|
||||
|
@ -1408,6 +1415,7 @@
|
|||
EDE243D52B6CF3980057369B /* AboutController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutController.swift; sourceTree = "<group>"; };
|
||||
EDE243E02B6D3EA00057369B /* InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = "<group>"; };
|
||||
EDE243E42B6D3F400057369B /* OSMView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSMView.swift; sourceTree = "<group>"; };
|
||||
EDE8EAEA2C2DBB99002777F5 /* OpenInApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInApplication.swift; sourceTree = "<group>"; };
|
||||
EDF838812C00B640007E4E67 /* SynchronizationFileWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizationFileWriter.swift; sourceTree = "<group>"; };
|
||||
EDF838AD2C00B9C7007E4E67 /* LocalDirectoryMonitorDelegateMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalDirectoryMonitorDelegateMock.swift; sourceTree = "<group>"; };
|
||||
EDF838AE2C00B9C7007E4E67 /* DefaultLocalDirectoryMonitorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultLocalDirectoryMonitorTests.swift; sourceTree = "<group>"; };
|
||||
|
@ -2915,6 +2923,7 @@
|
|||
99C964222428C0D500E41723 /* PlacePageHeader */,
|
||||
993DF0C223F6BD0600AC231A /* ElevationDetails */,
|
||||
99DEF9D523E420D2006BFD21 /* ElevationProfile */,
|
||||
EDE8EAE32C2DB74A002777F5 /* OpenInAppActionSheet */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2936,6 +2945,7 @@
|
|||
99C964252428C0F700E41723 /* PlacePageHeaderViewController.swift */,
|
||||
99C964262428C0F700E41723 /* PlacePageHeaderBuilder.swift */,
|
||||
99C9642F2428C27A00E41723 /* PlacePageHeaderView.swift */,
|
||||
ED808D0E2C38407800D52585 /* CircleImageButton.swift */,
|
||||
);
|
||||
path = PlacePageHeader;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3098,6 +3108,14 @@
|
|||
path = iCloud;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED9857022C4ECFFC00694F6C /* MailComposer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED9857072C4ED02D00694F6C /* MailComposer.swift */,
|
||||
);
|
||||
path = MailComposer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED99667C2B94FBC20083CE55 /* ColorPicker */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3106,6 +3124,15 @@
|
|||
path = ColorPicker;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EDE8EAE32C2DB74A002777F5 /* OpenInAppActionSheet */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EDE8EAEA2C2DBB99002777F5 /* OpenInApplication.swift */,
|
||||
ED77556D2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift */,
|
||||
);
|
||||
path = OpenInAppActionSheet;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EDF838AB2C00B9C7007E4E67 /* iCloudTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3349,6 +3376,7 @@
|
|||
F6E2FBFB1E097B9F0083EBEC /* UI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED9857022C4ECFFC00694F6C /* MailComposer */,
|
||||
ED43B8B92C12061600D07BAA /* DocumentPicker */,
|
||||
ED99667C2B94FBC20083CE55 /* ColorPicker */,
|
||||
F69018B51E9E5FEB00B3C10B /* Autoupdate */,
|
||||
|
@ -4355,6 +4383,7 @@
|
|||
3406FA161C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm in Sources */,
|
||||
340416481E7BF28E00E2B6D6 /* UIView+Snapshot.swift in Sources */,
|
||||
F6E2FE251E097BA00083EBEC /* MWMOpeningHoursModel.mm in Sources */,
|
||||
ED77556E2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift in Sources */,
|
||||
99AAEA74244DA5ED0039D110 /* BottomMenuPresentationController.swift in Sources */,
|
||||
99514BB823E82B450085D3A7 /* ElevationProfilePresenter.swift in Sources */,
|
||||
34C9BD031C6DB693000DC38D /* MWMTableViewController.m in Sources */,
|
||||
|
@ -4477,10 +4506,12 @@
|
|||
FA8E808925F412E2002A1434 /* FirstSession.mm in Sources */,
|
||||
F6E2FF691E097BA00083EBEC /* MWMUnitsController.mm in Sources */,
|
||||
6741AA031BF340DE002C974C /* MWMActivityViewController.mm in Sources */,
|
||||
ED808D0F2C38407800D52585 /* CircleImageButton.swift in Sources */,
|
||||
CDCA27382237F1BD00167D87 /* BookmarkInfo.swift in Sources */,
|
||||
993DF11A23F6BDB100AC231A /* UIBarButtonItemRenderer.swift in Sources */,
|
||||
34AB668C1FC5AA330078E451 /* NavigationStreetNameView.swift in Sources */,
|
||||
993DF12923F6BDB100AC231A /* ThemeManager.swift in Sources */,
|
||||
EDE8EAEB2C2DBB99002777F5 /* OpenInApplication.swift in Sources */,
|
||||
337F98A621D37B7400C8AC27 /* SearchTabViewController.swift in Sources */,
|
||||
3404755F1E081A4600C92850 /* MWMLocationPredictor.mm in Sources */,
|
||||
993DF11523F6BDB100AC231A /* UISearchBarRenderer.swift in Sources */,
|
||||
|
@ -4537,6 +4568,7 @@
|
|||
3404164C1E7BF42E00E2B6D6 /* UIView+Coordinates.swift in Sources */,
|
||||
99F3EB0323F4178200C713F8 /* PlacePageCommonLayout.swift in Sources */,
|
||||
99C6532223F2F506004322F3 /* IPlacePageLayout.swift in Sources */,
|
||||
ED9857082C4ED02D00694F6C /* MailComposer.swift in Sources */,
|
||||
99F8B4C623B644A6009FF0B4 /* MapStyleSheet.swift in Sources */,
|
||||
99012851244732DB00C72B10 /* BottomTabBarViewController.swift in Sources */,
|
||||
F63AF5061EA6162400A1DB98 /* FilterTypeCell.swift in Sources */,
|
||||
|
|
|
@ -92,6 +92,14 @@
|
|||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>mailto</string>
|
||||
<string>comgooglemaps</string>
|
||||
<string>osmandmaps</string>
|
||||
<string>yandexmaps</string>
|
||||
<string>dgis</string>
|
||||
<string>citymapper</string>
|
||||
<string>moovit</string>
|
||||
<string>uber</string>
|
||||
<string>waze</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
|
|
|
@ -5,9 +5,6 @@ extension LocalMetadataItem {
|
|||
lastModificationDate: TimeInterval) -> LocalMetadataItem {
|
||||
let item = LocalMetadataItem(fileName: fileName,
|
||||
fileUrl: URL(string: "url")!,
|
||||
fileSize: 0,
|
||||
contentType: "",
|
||||
creationDate: Date().timeIntervalSince1970,
|
||||
lastModificationDate: lastModificationDate)
|
||||
return item
|
||||
|
||||
|
@ -22,10 +19,7 @@ extension CloudMetadataItem {
|
|||
hasUnresolvedConflicts: Bool = false) -> CloudMetadataItem {
|
||||
let item = CloudMetadataItem(fileName: fileName,
|
||||
fileUrl: URL(string: "url")!,
|
||||
fileSize: 0,
|
||||
contentType: "",
|
||||
isDownloaded: isDownloaded,
|
||||
creationDate: Date().timeIntervalSince1970,
|
||||
lastModificationDate: lastModificationDate,
|
||||
isRemoved: isInTrash,
|
||||
downloadingError: nil,
|
||||
|
|
|
@ -4,7 +4,6 @@ protocol BottomMenuInteractorProtocol: AnyObject {
|
|||
func downloadMaps()
|
||||
func donate()
|
||||
func openSettings()
|
||||
func shareLocation(cell: BottomMenuItemCell)
|
||||
}
|
||||
|
||||
@objc protocol BottomMenuDelegate {
|
||||
|
@ -61,17 +60,4 @@ extension BottomMenuInteractor: BottomMenuInteractorProtocol {
|
|||
close()
|
||||
mapViewController?.performSegue(withIdentifier: "Map2Settings", sender: nil)
|
||||
}
|
||||
|
||||
func shareLocation(cell: BottomMenuItemCell) {
|
||||
let lastLocation = LocationManager.lastLocation()
|
||||
guard let coordinates = lastLocation?.coordinate else {
|
||||
let alert = UIAlertController(title: L("unknown_current_position"), message: nil, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: L("ok"), style: .default, handler: nil))
|
||||
viewController?.present(alert, animated: true, completion: nil)
|
||||
return;
|
||||
}
|
||||
guard let viewController = viewController else { return }
|
||||
let vc = ActivityViewController.share(forMyPosition: coordinates)
|
||||
vc?.present(inParentViewController: viewController, anchorView: cell.anchorView)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ class BottomMenuPresenter: NSObject {
|
|||
case downloadMaps
|
||||
case donate
|
||||
case settings
|
||||
case share
|
||||
}
|
||||
enum Sections: Int {
|
||||
case layers
|
||||
|
@ -60,7 +59,7 @@ extension BottomMenuPresenter {
|
|||
let cell = tableView.dequeueReusableCell(cell: BottomMenuItemCell.self)!
|
||||
switch CellType(rawValue: correctedRow(indexPath.row))! {
|
||||
case .addPlace:
|
||||
let enabled = MWMNavigationDashboardManager.shared().state == .hidden && FrameworkHelper.canEditMap()
|
||||
let enabled = MWMNavigationDashboardManager.shared().state == .hidden && FrameworkHelper.canEditMapAtViewportCenter()
|
||||
cell.configure(imageName: "ic_add_place",
|
||||
title: L("placepage_add_place_button"),
|
||||
badgeCount: 0,
|
||||
|
@ -80,11 +79,6 @@ extension BottomMenuPresenter {
|
|||
title: L("settings"),
|
||||
badgeCount: 0,
|
||||
enabled: true)
|
||||
case .share:
|
||||
cell.configure(imageName: "ic_menu_share",
|
||||
title: L("share_my_location"),
|
||||
badgeCount: 0,
|
||||
enabled: true)
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
@ -94,6 +88,13 @@ extension BottomMenuPresenter {
|
|||
//MARK: -- UITableDelegate
|
||||
|
||||
extension BottomMenuPresenter {
|
||||
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
if let cell = tableView.cellForRow(at: indexPath) as? BottomMenuItemCell {
|
||||
return cell.isEnabled ? indexPath : nil
|
||||
}
|
||||
return indexPath
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
guard indexPath.section == Sections.items.rawValue else {
|
||||
return
|
||||
|
@ -108,10 +109,6 @@ extension BottomMenuPresenter {
|
|||
interactor.donate()
|
||||
case .settings:
|
||||
interactor.openSettings()
|
||||
case .share:
|
||||
if let cell = tableView.cellForRow(at: indexPath) as? BottomMenuItemCell {
|
||||
interactor.shareLocation(cell: cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class BottomMenuItemCell: UITableViewCell {
|
|||
}
|
||||
}
|
||||
|
||||
private var isEnabled: Bool = true
|
||||
private(set) var isEnabled: Bool = true
|
||||
private var isPromo: Bool = false
|
||||
|
||||
func configure(imageName: String, title: String, badgeCount: UInt, enabled: Bool) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import UIKit
|
||||
|
||||
class BottomMenuLayersCell: UITableViewCell {
|
||||
@IBOutlet weak var closeButton: CircleImageButton!
|
||||
|
||||
@IBOutlet private var subwayButton: BottomMenuLayerButton! {
|
||||
didSet {
|
||||
updateSubwayButton()
|
||||
|
@ -22,6 +24,7 @@ class BottomMenuLayersCell: UITableViewCell {
|
|||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
MapOverlayManager.add(self)
|
||||
closeButton.setImage(UIImage(named: "ic_close"))
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<device id="ipad9_7" orientation="landscape" layout="fullscreen" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -30,16 +30,12 @@
|
|||
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="layers_title"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2xW-dK-D9y">
|
||||
<rect key="frame" x="294" y="10" width="30" height="30"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2xW-dK-D9y" customClass="CircleImageButton" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="296" y="11" width="28" height="28"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="BD2-bz-n13"/>
|
||||
<constraint firstAttribute="width" constant="30" id="Thu-MY-dQm"/>
|
||||
<constraint firstAttribute="height" constant="28" id="BD2-bz-n13"/>
|
||||
<constraint firstAttribute="width" constant="28" id="Thu-MY-dQm" customClass="I"/>
|
||||
</constraints>
|
||||
<state key="normal" image="ic_clear_24"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="PPCloseButton"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="onCloseButtonPressed:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="8vd-Pg-Suh"/>
|
||||
</connections>
|
||||
|
@ -189,6 +185,7 @@
|
|||
<constraint firstItem="njF-e1-oar" firstAttribute="leading" secondItem="75k-vD-FSR" secondAttribute="leading" id="nhe-Sa-Mlo"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="closeButton" destination="2xW-dK-D9y" id="RQI-hb-JpS"/>
|
||||
<outlet property="isoLinesButton" destination="edA-Mo-3Vx" id="qoC-8w-EqY"/>
|
||||
<outlet property="outdoorButton" destination="g13-pK-Eig" id="ib1-aw-Qv9"/>
|
||||
<outlet property="subwayButton" destination="4US-fZ-cyg" id="eQB-HR-Wgl"/>
|
||||
|
@ -200,6 +197,5 @@
|
|||
<image name="btn_menu_isomaps" width="151" height="151"/>
|
||||
<image name="btn_menu_outdoors" width="151" height="151"/>
|
||||
<image name="btn_menu_subway" width="151" height="151"/>
|
||||
<image name="ic_clear_24" width="20" height="20"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
@ -282,7 +282,7 @@ private extension AboutController {
|
|||
let logFileURL = Logger.getLogFileURL()
|
||||
UIApplication.shared.hideLoadingOverlay {
|
||||
guard let self else { return }
|
||||
self.sendEmailWith(header: "Organic Maps Bugreport", toRecipients: [link], attachmentFileURL: logFileURL)
|
||||
MailComposer.default.sendEmailWith(header: "Organic Maps Bugreport", toRecipients: [link], attachmentFileURL: logFileURL)
|
||||
}
|
||||
}
|
||||
case .reportMapDataProblem, .volunteer, .news:
|
||||
|
@ -314,7 +314,7 @@ private extension AboutController {
|
|||
self?.openUrl(socialMedia.link, externally: true)
|
||||
case .organicMapsEmail:
|
||||
guard let link = socialMedia.link else { fatalError("The Organic Maps email link should be provided.") }
|
||||
self?.sendEmailWith(header: "Organic Maps", toRecipients: [link])
|
||||
MailComposer.default.sendEmailWith(header: "Organic Maps", toRecipients: [link])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -441,111 +441,6 @@ extension AboutController: UICollectionViewDelegateFlowLayout {
|
|||
return Constants.socialMediaCollectionViewSpacing
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Mail Composing
|
||||
private extension AboutController {
|
||||
func sendEmailWith(header: String, toRecipients: [String], attachmentFileURL: URL? = nil) {
|
||||
func emailSubject(subject: String) -> String {
|
||||
let appInfo = AppInfo.shared()
|
||||
return String(format:"[%@-%@ iOS] %@", appInfo.bundleVersion, appInfo.buildNumber, subject)
|
||||
}
|
||||
|
||||
func emailBody() -> String {
|
||||
let appInfo = AppInfo.shared()
|
||||
return String(format: "\n\n\n\n- %@ (%@)\n- Organic Maps %@-%@\n- %@-%@\n- %@\n",
|
||||
appInfo.deviceModel, UIDevice.current.systemVersion,
|
||||
appInfo.bundleVersion, appInfo.buildNumber,
|
||||
Locale.current.languageCode ?? "",
|
||||
Locale.current.regionCode ?? "",
|
||||
Locale.preferredLanguages.joined(separator: ", "))
|
||||
}
|
||||
|
||||
func openOutlook(subject: String, body: String, recipients: [String]) -> Bool {
|
||||
var components = URLComponents(string: "ms-outlook://compose")!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "to", value: recipients.joined(separator: ";")),
|
||||
URLQueryItem(name: "subject", value: subject),
|
||||
URLQueryItem(name: "body", value: body),
|
||||
]
|
||||
|
||||
if let url = components.url, UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func openGmail(subject: String, body: String, recipients: [String]) -> Bool {
|
||||
var components = URLComponents(string: "googlegmail://co")!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "to", value: recipients.joined(separator: ";")),
|
||||
URLQueryItem(name: "subject", value: subject),
|
||||
URLQueryItem(name: "body", value: body),
|
||||
]
|
||||
|
||||
if let url = components.url, UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func openDefaultMailApp(subject: String, body: String, recipients: [String]) -> Bool {
|
||||
var components = URLComponents(string: "mailto:\(recipients.joined(separator: ";"))")
|
||||
components?.queryItems = [
|
||||
URLQueryItem(name: "subject", value: subject),
|
||||
URLQueryItem(name: "body", value: body.replacingOccurrences(of: "\n", with: "\r\n")),
|
||||
]
|
||||
|
||||
if let url = components?.url, UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func showMailComposingAlert() {
|
||||
let text = String(format:L("email_error_body"), toRecipients.joined(separator: ";"))
|
||||
let alert = UIAlertController(title: L("email_error_title"), message: text, preferredStyle: .alert)
|
||||
let action = UIAlertAction(title: L("ok"), style: .default, handler: nil)
|
||||
alert.addAction(action)
|
||||
present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
let subject = emailSubject(subject: header)
|
||||
let body = emailBody()
|
||||
|
||||
// If the attachment file path is provided, the default mail composer should be used.
|
||||
if let attachmentFileURL {
|
||||
if MWMMailViewController.canSendMail(), let attachmentData = try? Data(contentsOf: attachmentFileURL) {
|
||||
let mailViewController = MWMMailViewController()
|
||||
mailViewController.mailComposeDelegate = self
|
||||
mailViewController.setSubject(subject)
|
||||
mailViewController.setMessageBody(body, isHTML:false)
|
||||
mailViewController.setToRecipients(toRecipients)
|
||||
mailViewController.addAttachmentData(attachmentData, mimeType: "application/zip", fileName: attachmentFileURL.lastPathComponent)
|
||||
|
||||
self.present(mailViewController, animated: true, completion:nil)
|
||||
} else {
|
||||
showMailComposingAlert()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Before iOS 14, try to open alternate email apps first, assuming that if users installed them, they're using them.
|
||||
let os = ProcessInfo().operatingSystemVersion
|
||||
if (os.majorVersion < 14 && (openGmail(subject: subject, body: body, recipients: toRecipients) ||
|
||||
openOutlook(subject: subject, body: body, recipients: toRecipients))) {
|
||||
return
|
||||
}
|
||||
|
||||
// From iOS 14, it is possible to change the default mail app, and mailto should open a default mail app.
|
||||
if !openDefaultMailApp(subject: subject, body: body, recipients: toRecipients) {
|
||||
showMailComposingAlert()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIStackView + AddArrangedSubviewWithSeparator
|
||||
private extension UIStackView {
|
||||
func addArrangedSubviewWithSeparator(_ view: UIView) {
|
||||
|
@ -564,10 +459,3 @@ private extension UIStackView {
|
|||
addArrangedSubview(view)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MFMailComposeViewControllerDelegate
|
||||
extension AboutController: MFMailComposeViewControllerDelegate {
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
115
iphone/Maps/UI/MailComposer/MailComposer.swift
Normal file
|
@ -0,0 +1,115 @@
|
|||
final class MailComposer: NSObject {
|
||||
|
||||
static let `default` = MailComposer()
|
||||
|
||||
private var topViewController: UIViewController { UIViewController.topViewController() }
|
||||
|
||||
private override init() {}
|
||||
|
||||
func sendEmailWith(header: String, toRecipients: [String], attachmentFileURL: URL? = nil) {
|
||||
func emailSubject(subject: String) -> String {
|
||||
let appInfo = AppInfo.shared()
|
||||
return String(format:"[%@-%@ iOS] %@", appInfo.bundleVersion, appInfo.buildNumber, subject)
|
||||
}
|
||||
|
||||
func emailBody() -> String {
|
||||
let appInfo = AppInfo.shared()
|
||||
return String(format: "\n\n\n\n- %@ (%@)\n- Organic Maps %@-%@\n- %@-%@\n- %@\n",
|
||||
appInfo.deviceModel, UIDevice.current.systemVersion,
|
||||
appInfo.bundleVersion, appInfo.buildNumber,
|
||||
Locale.current.languageCode ?? "",
|
||||
Locale.current.regionCode ?? "",
|
||||
Locale.preferredLanguages.joined(separator: ", "))
|
||||
}
|
||||
|
||||
func openOutlook(subject: String, body: String, recipients: [String]) -> Bool {
|
||||
var components = URLComponents(string: "ms-outlook://compose")!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "to", value: recipients.joined(separator: ";")),
|
||||
URLQueryItem(name: "subject", value: subject),
|
||||
URLQueryItem(name: "body", value: body),
|
||||
]
|
||||
|
||||
if let url = components.url, UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func openGmail(subject: String, body: String, recipients: [String]) -> Bool {
|
||||
var components = URLComponents(string: "googlegmail://co")!
|
||||
components.queryItems = [
|
||||
URLQueryItem(name: "to", value: recipients.joined(separator: ";")),
|
||||
URLQueryItem(name: "subject", value: subject),
|
||||
URLQueryItem(name: "body", value: body),
|
||||
]
|
||||
|
||||
if let url = components.url, UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func openDefaultMailApp(subject: String, body: String, recipients: [String]) -> Bool {
|
||||
var components = URLComponents(string: "mailto:\(recipients.joined(separator: ";"))")
|
||||
components?.queryItems = [
|
||||
URLQueryItem(name: "subject", value: subject),
|
||||
URLQueryItem(name: "body", value: body.replacingOccurrences(of: "\n", with: "\r\n")),
|
||||
]
|
||||
|
||||
if let url = components?.url, UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func showMailComposingAlert() {
|
||||
let text = String(format:L("email_error_body"), toRecipients.joined(separator: ";"))
|
||||
let alert = UIAlertController(title: L("email_error_title"), message: text, preferredStyle: .alert)
|
||||
let action = UIAlertAction(title: L("ok"), style: .default, handler: nil)
|
||||
alert.addAction(action)
|
||||
topViewController.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
let subject = emailSubject(subject: header)
|
||||
let body = emailBody()
|
||||
|
||||
// If the attachment file path is provided, the default mail composer should be used.
|
||||
if let attachmentFileURL {
|
||||
if MWMMailViewController.canSendMail(), let attachmentData = try? Data(contentsOf: attachmentFileURL) {
|
||||
let mailViewController = MWMMailViewController()
|
||||
mailViewController.mailComposeDelegate = self
|
||||
mailViewController.setSubject(subject)
|
||||
mailViewController.setMessageBody(body, isHTML:false)
|
||||
mailViewController.setToRecipients(toRecipients)
|
||||
mailViewController.addAttachmentData(attachmentData, mimeType: "application/zip", fileName: attachmentFileURL.lastPathComponent)
|
||||
topViewController.present(mailViewController, animated: true, completion:nil)
|
||||
} else {
|
||||
showMailComposingAlert()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Before iOS 14, try to open alternate email apps first, assuming that if users installed them, they're using them.
|
||||
let os = ProcessInfo().operatingSystemVersion
|
||||
if (os.majorVersion < 14 && (openGmail(subject: subject, body: body, recipients: toRecipients) ||
|
||||
openOutlook(subject: subject, body: body, recipients: toRecipients))) {
|
||||
return
|
||||
}
|
||||
|
||||
// From iOS 14, it is possible to change the default mail app, and mailto should open a default mail app.
|
||||
if !openDefaultMailApp(subject: subject, body: body, recipients: toRecipients) {
|
||||
showMailComposingAlert()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MFMailComposeViewControllerDelegate
|
||||
extension MailComposer: MFMailComposeViewControllerDelegate {
|
||||
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
controller.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
|
@ -151,10 +151,7 @@ class ActionBarViewController: UIViewController {
|
|||
}
|
||||
|
||||
private func configButton4() {
|
||||
if additionalButtons.isEmpty {
|
||||
visibleButtons.append(.share)
|
||||
} else {
|
||||
additionalButtons.append(.share)
|
||||
if !additionalButtons.isEmpty {
|
||||
visibleButtons.append(.more)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
enum OpenInApplication: Int, CaseIterable {
|
||||
case osm
|
||||
case googleMaps
|
||||
case appleMaps
|
||||
case osmAnd
|
||||
case yandexMaps
|
||||
case dGis
|
||||
case cityMapper
|
||||
case moovit
|
||||
case uber
|
||||
case waze
|
||||
}
|
||||
|
||||
extension OpenInApplication {
|
||||
|
||||
static var allCases: [OpenInApplication] {
|
||||
[
|
||||
.osm,
|
||||
.googleMaps,
|
||||
.appleMaps,
|
||||
.osmAnd,
|
||||
.yandexMaps,
|
||||
.dGis,
|
||||
.cityMapper,
|
||||
.moovit,
|
||||
.uber,
|
||||
.waze
|
||||
]
|
||||
}
|
||||
|
||||
static var availableApps: [OpenInApplication] {
|
||||
// OSM should always be first in the list.
|
||||
let sortedApps: [OpenInApplication] = [.osm] + allCases.filter { $0 != .osm }.sorted(by: { $0.name < $1.name })
|
||||
return sortedApps.filter { UIApplication.shared.canOpenURL(URL(string: $0.scheme)!) }
|
||||
}
|
||||
|
||||
var name: String {
|
||||
switch self {
|
||||
case .osm:
|
||||
return "OpenStreetMap"
|
||||
case .googleMaps:
|
||||
return "Google Maps"
|
||||
case .appleMaps:
|
||||
return "Apple Maps"
|
||||
case .osmAnd:
|
||||
return "OsmAnd Maps"
|
||||
case .yandexMaps:
|
||||
return "Yandex Maps"
|
||||
case .dGis:
|
||||
return "2GIS"
|
||||
case .cityMapper:
|
||||
return "Citymapper"
|
||||
case .moovit:
|
||||
return "Moovit"
|
||||
case .uber:
|
||||
return "Uber"
|
||||
case .waze:
|
||||
return "Waze"
|
||||
}
|
||||
}
|
||||
|
||||
// Schemes should be registered in LSApplicationQueriesSchemes - see Info.plist.
|
||||
var scheme: String {
|
||||
switch self {
|
||||
case .osm:
|
||||
return "https://osm.org/go/"
|
||||
case .googleMaps:
|
||||
return "comgooglemaps://"
|
||||
case .appleMaps:
|
||||
return "https://maps.apple.com/"
|
||||
case .osmAnd:
|
||||
return "osmandmaps://"
|
||||
case .yandexMaps:
|
||||
return "yandexmaps://"
|
||||
case .dGis:
|
||||
return "dgis://"
|
||||
case .cityMapper:
|
||||
return "citymapper://"
|
||||
case .moovit:
|
||||
return "moovit://"
|
||||
case .uber:
|
||||
return "uber://"
|
||||
case .waze:
|
||||
return "waze://"
|
||||
}
|
||||
}
|
||||
|
||||
func linkWith(coordinates: CLLocationCoordinate2D, zoomLevel: Int = Int(FrameworkHelper.currentZoomLevel()), destinationName: String? = nil) -> String {
|
||||
let latitude = String(format: "%.6f", coordinates.latitude)
|
||||
let longitude = String(format: "%.6f", coordinates.longitude)
|
||||
switch self {
|
||||
case .osm:
|
||||
return GeoUtil.formattedOsmLink(for: coordinates, zoomLevel: Int32(zoomLevel))
|
||||
case .googleMaps:
|
||||
return "\(scheme)?&q=\(latitude),\(longitude)&z=\(zoomLevel)"
|
||||
case .appleMaps:
|
||||
if let destinationName {
|
||||
return "\(scheme)?q=\(destinationName)&ll=\(latitude),\(longitude)&z=\(zoomLevel)"
|
||||
}
|
||||
return "\(scheme)?ll=\(latitude),\(longitude)&z=\(zoomLevel)"
|
||||
case .osmAnd:
|
||||
if let destinationName {
|
||||
return "\(scheme)?lat=\(latitude)&lon=\(longitude)&z=\(zoomLevel)&title=\(destinationName)"
|
||||
}
|
||||
return "\(scheme)?lat=\(latitude)&lon=\(longitude)&z=\(zoomLevel)"
|
||||
case .yandexMaps:
|
||||
return "\(scheme)maps.yandex.ru/?pt=\(longitude),\(latitude)&z=\(zoomLevel)"
|
||||
case .dGis:
|
||||
return "\(scheme)2gis.ru/geo/\(longitude),\(latitude)"
|
||||
case .cityMapper:
|
||||
return "\(scheme)directions?endcoord=\(latitude),\(longitude)&endname=\(destinationName ?? "")"
|
||||
case .moovit:
|
||||
if let destinationName {
|
||||
return "\(scheme)directions?dest_lat=\(latitude)&dest_lon=\(longitude)&dest_name=\(destinationName)"
|
||||
}
|
||||
return "\(scheme)directions?dest_lat=\(latitude)&dest_lon=\(longitude)"
|
||||
case .uber:
|
||||
return "\(scheme)?client_id=&action=setPickup&pickup=my_location&dropoff[latitude]=\(latitude)&dropoff[longitude]=\(longitude)"
|
||||
case .waze:
|
||||
return "\(scheme)?ll=\(latitude),\(longitude)"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
typealias OpenInApplicationCompletionHandler = (OpenInApplication) -> Void
|
||||
|
||||
extension UIAlertController {
|
||||
static func presentInAppActionSheet(from sourceView: UIView,
|
||||
apps: [OpenInApplication] = OpenInApplication.availableApps,
|
||||
didSelectApp: @escaping OpenInApplicationCompletionHandler) -> UIAlertController {
|
||||
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
|
||||
apps.forEach { app in
|
||||
let action = UIAlertAction(title: app.name, style: .default) { _ in
|
||||
didSelectApp(app)
|
||||
}
|
||||
alertController.addAction(action)
|
||||
}
|
||||
|
||||
let cancelAction = UIAlertAction(title: L("cancel"), style: .cancel)
|
||||
alertController.addAction(cancelAction)
|
||||
|
||||
iPadSpecific {
|
||||
alertController.popoverPresentationController?.sourceView = sourceView
|
||||
alertController.popoverPresentationController?.sourceRect = sourceView.bounds
|
||||
}
|
||||
return alertController
|
||||
}
|
||||
}
|
|
@ -1,18 +1,13 @@
|
|||
protocol PlacePageButtonsViewControllerDelegate: AnyObject {
|
||||
func didPressHotels()
|
||||
func didPressAddPlace()
|
||||
func didPressEditPlace()
|
||||
func didPressAddBusiness()
|
||||
}
|
||||
|
||||
class PlacePageButtonsViewController: UIViewController {
|
||||
// @IBOutlet var bookingButton: UIButton!
|
||||
@IBOutlet var addPlaceButton: UIButton!
|
||||
@IBOutlet var editPlaceButton: UIButton!
|
||||
// @IBOutlet var addBusinessButton: UIButton!
|
||||
|
||||
private var buttons: [UIButton?] {
|
||||
// [bookingButton, addPlaceButton, editPlaceButton, addBusinessButton]
|
||||
[addPlaceButton, editPlaceButton]
|
||||
}
|
||||
|
||||
|
@ -30,18 +25,11 @@ class PlacePageButtonsViewController: UIViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// bookingButton.isHidden = !buttonsData.showHotelDescription
|
||||
addPlaceButton.isHidden = !buttonsData.showAddPlace
|
||||
editPlaceButton.isHidden = !buttonsData.showEditPlace
|
||||
// addBusinessButton.isHidden = !buttonsData.showAddBusiness
|
||||
|
||||
buttons.forEach {
|
||||
$0?.isEnabled = buttonsEnabled
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func onBooking(_ sender: UIButton) {
|
||||
delegate?.didPressHotels()
|
||||
addPlaceButton.isEnabled = buttonsData.enableAddPlace
|
||||
editPlaceButton.isEnabled = buttonsData.enableEditPlace
|
||||
}
|
||||
|
||||
@IBAction func onAddPlace(_ sender: UIButton) {
|
||||
|
@ -51,8 +39,4 @@ class PlacePageButtonsViewController: UIViewController {
|
|||
@IBAction func onEditPlace(_ sender: UIButton) {
|
||||
delegate?.didPressEditPlace()
|
||||
}
|
||||
|
||||
@IBAction func onAddBusiness(_ sender: UIButton) {
|
||||
delegate?.didPressAddBusiness()
|
||||
}
|
||||
}
|
||||
|
|