Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
1
1weather
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
1weather
Commits
899bbabd
Commit
899bbabd
authored
Apr 29, 2021
by
Demid Merzlyakov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
All menu items are functioning.
parent
72ede3bb
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
228 additions
and
5 deletions
+228
-5
1Weather.xcodeproj/project.pbxproj
+4
-0
1Weather/Common/Constants.swift
+7
-0
1Weather/Extensions/UIDevice+Convenience.swift
+21
-0
1Weather/Network/PushNotificationsManager.swift
+4
-1
1Weather/Resources/Assets.xcassets/menu/menu_device_id.imageset/Contents.json
+16
-0
1Weather/Resources/Assets.xcassets/menu/menu_device_id.imageset/group.pdf
+0
-0
1Weather/Resources/en.lproj/Localizable.strings
+7
-0
1Weather/UI/View controllers/Menu/Cells/MenuCellFactory.swift
+8
-1
1Weather/UI/View controllers/Menu/MenuViewController.swift
+28
-2
1Weather/ViewModels/MenuViewModel.swift
+133
-1
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
899bbabd
...
...
@@ -211,6 +211,7 @@
CE849DB82638C33600DEFFBD
/* NotificationService.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE849DB72638C33600DEFFBD
/* NotificationService.swift */
;
};
CE849DBC2638C33600DEFFBD
/* OneWeatherNotificationServiceExtension.appex in Embed App Extensions */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE849DB52638C33600DEFFBD
/* OneWeatherNotificationServiceExtension.appex */
;
settings
=
{
ATTRIBUTES
=
(
RemoveHeadersOnCopy
,
);
};
};
CE849E382638CE8000DEFFBD
/* UserNotifications.framework in Frameworks */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE849E372638CE8000DEFFBD
/* UserNotifications.framework */
;
};
CE8805D3263AEEE6003C53B7
/* UIDevice+Convenience.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE8805D2263AEEE6003C53B7
/* UIDevice+Convenience.swift */
;
};
CE895F0F26393FD800214175
/* WeatherImageProvider.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE895F0E26393FD800214175
/* WeatherImageProvider.swift */
;
};
CE89628C26175D8D00CA274A
/* regenerate_objects.sh in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE89628B26175D8D00CA274A
/* regenerate_objects.sh */
;
};
CE8962A226175DF500CA274A
/* _CoreAirQuality.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CE89629126175DF400CA274A
/* _CoreAirQuality.swift */
;
};
...
...
@@ -535,6 +536,7 @@
CE849DB92638C33600DEFFBD
/* Info.plist */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
text.plist.xml
;
path
=
Info.plist
;
sourceTree
=
"<group>"
;
};
CE849DE82638C59800DEFFBD
/* OneWeatherNotificationServiceExtension.entitlements */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
text.plist.entitlements
;
path
=
OneWeatherNotificationServiceExtension.entitlements
;
sourceTree
=
"<group>"
;
};
CE849E372638CE8000DEFFBD
/* UserNotifications.framework */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
wrapper.framework
;
name
=
UserNotifications.framework
;
path
=
System/Library/Frameworks/UserNotifications.framework
;
sourceTree
=
SDKROOT
;
};
CE8805D2263AEEE6003C53B7
/* UIDevice+Convenience.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
"UIDevice+Convenience.swift"
;
sourceTree
=
"<group>"
;
};
CE895F0E26393FD800214175
/* WeatherImageProvider.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WeatherImageProvider.swift
;
sourceTree
=
"<group>"
;
};
CE89628B26175D8D00CA274A
/* regenerate_objects.sh */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text.script.sh
;
path
=
regenerate_objects.sh
;
sourceTree
=
"<group>"
;
};
CE89629126175DF400CA274A
/* _CoreAirQuality.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
_CoreAirQuality.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -739,6 +741,7 @@
CDF48091261729680076E9F5
/* UIApplication+Settings.swift */
,
CD67616C262587D30079D273
/* UITabBarController+Hide.swift */
,
CD43DF022636C6640010C9F7
/* CACornerMask+All.swift */
,
CE8805D2263AEEE6003C53B7
/* UIDevice+Convenience.swift */
,
);
path
=
Extensions
;
sourceTree
=
"<group>"
;
...
...
@@ -2031,6 +2034,7 @@
CD35DFCC260341B000F2138F
/* Calendar+TimeZone.swift in Sources */
,
CD9B6B1125DBC723001D9B80
/* CubicCurveAlgorithm.swift in Sources */
,
CD8B60B4263819790055CB3F
/* NotificationsViewController.swift in Sources */
,
CE8805D3263AEEE6003C53B7
/* UIDevice+Convenience.swift in Sources */
,
CEC5270025E7BACB00DA58A5
/* WdtLocation.swift in Sources */
,
CE8962A726175DF500CA274A
/* _CoreLocation.swift in Sources */
,
CD67617026259D220079D273
/* RadarMapLayersController.swift in Sources */
,
...
...
1Weather/Common/Constants.swift
View file @
899bbabd
...
...
@@ -15,3 +15,10 @@ let kAdMoPubInitializationAdUnitId = "05bff78d4a4245bd98ff6b595c134889"
let
kOLAppMetricsKey
:
String
=
"OLAppMetricsKey"
//MARK: - InApp
let
kInAppOneWeatherProId
=
"com.onelouder.oneweather.inapp1"
let
ONE_WEATHER_ABOUT_US_URL
=
"https://1weatherapp.com/"
let
ONE_WEATHER_PRIVACY_URL
=
"https://1weatherapp.com/privacy"
let
ONE_WEATHER_PRIVACY_OPTOUT_URL
=
"https://1weatherapp.com/privacy#opt-out"
let
ONE_WEATHER_FAQ_URL
=
"https://support.onelouder.com/hc/en-us/sections/201336846"
let
ONE_WEATHER_URL
=
"https://pinsightmedia.com/solutions/onelouder"
let
ONE_WEATHER_LICENSES_URL
=
"https://onelouder-1weather.s3.amazonaws.com/attribution.html"
1Weather/Extensions/UIDevice+Convenience.swift
0 → 100644
View file @
899bbabd
//
// UIDevice+Convenience.swift
// 1Weather
//
// Created by Demid Merzlyakov on 29.04.2021.
//
import
UIKit
public
extension
UIDevice
{
var
modelName
:
String
{
var
systemInfo
=
utsname
()
uname
(
&
systemInfo
)
let
machineMirror
=
Mirror
(
reflecting
:
systemInfo
.
machine
)
let
identifier
=
machineMirror
.
children
.
reduce
(
""
)
{
identifier
,
element
in
guard
let
value
=
element
.
value
as?
Int8
,
value
!=
0
else
{
return
identifier
}
return
identifier
+
String
(
UnicodeScalar
(
UInt8
(
value
)))
}
return
identifier
}
}
1Weather/Network/PushNotificationsManager.swift
View file @
899bbabd
...
...
@@ -80,8 +80,11 @@ public class PushNotificationsManager: NSObject {
updateNwsSubscriptions
(
with
:
newFipsList
,
currentFipsCode
:
selectedLocation
?
.
fipsCode
)
}
var
lastKnownPushToken
:
String
?
public
func
set
(
pushToken
:
Data
)
{
let
tokenString
=
pushToken
.
map
{
String
(
format
:
"%02.2hhx"
,
$0
)
}
.
joined
()
self
.
lastKnownPushToken
=
tokenString
log
.
info
(
"Got new APNS token:
\(
tokenString
)
"
)
MoEngage
.
sharedInstance
()
.
setPushToken
(
pushToken
)
}
...
...
@@ -89,7 +92,7 @@ public class PushNotificationsManager: NSObject {
extension
PushNotificationsManager
:
ConfigManagerDelegate
{
public
func
dataUpdated
(
by
configManager
:
ConfigManager
)
{
updateNwsSubscriptions
(
with
:
lastSetFIPSList
)
updateNwsSubscriptions
(
with
:
lastSetFIPSList
,
currentFipsCode
:
lastSetFIPSCode
)
}
}
...
...
1Weather/Resources/Assets.xcassets/menu/menu_device_id.imageset/Contents.json
0 → 100644
View file @
899bbabd
{
"images"
:
[
{
"filename"
:
"group.pdf"
,
"idiom"
:
"universal"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
},
"properties"
:
{
"preserves-vector-representation"
:
true
,
"template-rendering-intent"
:
"template"
}
}
1Weather/Resources/Assets.xcassets/menu/menu_device_id.imageset/group.pdf
0 → 100644
View file @
899bbabd
File added
1Weather/Resources/en.lproj/Localizable.strings
View file @
899bbabd
...
...
@@ -14,6 +14,7 @@
"general.ok" = "Ok";
"general.cancel" = "Cancel";
"general.continue" = "Continue";
"general.copy" = "Copy";
//Alert
"today.alert.infoTemplate.oneAlert" = "#ALERT_DESCRIPTION";
...
...
@@ -183,7 +184,13 @@
"menu.help" = "Help";
"menu.faq" = "FAQ's";
"menu.privacy" = "Privacy Policy";
"menu.deviceId" = "Device Identifier";
"menu.version" = "version";
"menu.deviceId.notAvailable.title" = "Identifier not available";
"menu.deviceId.notAvailable.text" = "Identifier for verndor is empty";
"menu.deviceId.title" = "Device Identifier";
"menu.deviceId.text" = "Your device identifier is: ";
"menu.help.unableToSendEmail.text" = "Device is unable to send email.";
//Settings
"settings.theme.automatic" = "Automatic";
...
...
1Weather/UI/View controllers/Menu/Cells/MenuCellFactory.swift
View file @
899bbabd
...
...
@@ -15,6 +15,7 @@ public enum MenuRow {
case
help
case
faq
case
privacy
case
deviceId
var
image
:
UIImage
?
{
switch
self
{
...
...
@@ -32,6 +33,8 @@ public enum MenuRow {
return
UIImage
(
named
:
"menu_faq"
)
case
.
privacy
:
return
UIImage
(
named
:
"menu_privacyPolicy"
)
case
.
deviceId
:
return
UIImage
(
named
:
"menu_device_id"
)
}
}
...
...
@@ -51,6 +54,8 @@ public enum MenuRow {
return
"menu.faq"
.
localized
()
case
.
privacy
:
return
"menu.privacy"
.
localized
()
case
.
deviceId
:
return
"menu.deviceId"
.
localized
()
}
}
...
...
@@ -69,6 +74,8 @@ public enum MenuRow {
case
.
faq
:
return
[]
case
.
privacy
:
return
[]
case
.
deviceId
:
return
[
.
layerMinXMaxYCorner
,
.
layerMaxXMaxYCorner
]
}
}
...
...
@@ -88,7 +95,7 @@ class MenuCellFactory<T>: CellFactoryProtocol {
//Private
private
let
menuViewModel
:
MenuViewModel
private
let
sections
:[
SectionItem
]
=
[
SectionItem
(
type
:
.
info
,
rows
:
[
.
settings
]),
SectionItem
(
type
:
.
settings
,
rows
:
[
.
about
,
.
ad
,
.
rateUs
,
.
help
,
.
faq
,
.
privacy
])]
SectionItem
(
type
:
.
settings
,
rows
:
[
.
about
,
.
ad
,
.
help
,
.
faq
,
.
privacy
,
.
deviceId
])]
//Public
public
var
kSectionHeight
:
CGFloat
{
...
...
1Weather/UI/View controllers/Menu/MenuViewController.swift
View file @
899bbabd
...
...
@@ -6,6 +6,7 @@
//
import
UIKit
import
SafariServices
class
MenuViewController
:
UIViewController
{
//Private
...
...
@@ -111,9 +112,23 @@ extension MenuViewController: UITableViewDelegate {
guard
let
type
=
menuCellFactory
.
cellTypeAt
(
indexPath
:
indexPath
)
else
{
return
}
if
type
==
.
settings
{
switch
type
{
case
.
about
:
viewModel
.
viewAboutUs
()
case
.
settings
:
coordinator
.
openSettings
()
case
.
faq
:
viewModel
.
viewFAQ
()
case
.
ad
:
viewModel
.
viewAdChoices
()
case
.
help
:
viewModel
.
showHelp
()
case
.
privacy
:
viewModel
.
viewPrivacyPolicy
()
case
.
deviceId
:
viewModel
.
showDeviceId
()
default
:
break
}
}
}
...
...
@@ -131,4 +146,15 @@ extension MenuViewController: MenuViewModelDelegate {
func
viewControllerForPresentation
()
->
UIViewController
{
return
self
}
func
presentWebView
(
url
urlString
:
String
)
{
if
let
url
=
URL
(
string
:
urlString
)
{
let
svc
=
SFSafariViewController
(
url
:
url
)
// svc.preferredBarTintColor = ThemeManager.Colors.primaryBackground
// svc.modalPresentationCapturesStatusBarAppearance = false
// svc.setNeedsStatusBarAppearanceUpdate()
self
.
present
(
svc
,
animated
:
true
,
completion
:
nil
)
}
}
}
1Weather/ViewModels/MenuViewModel.swift
View file @
899bbabd
...
...
@@ -7,13 +7,15 @@
import
UIKit
import
StoreKit
import
MessageUI
import
PKHUD
protocol
MenuViewModelDelegate
:
ViewModelDelegate
{
func
viewControllerForPresentation
()
->
UIViewController
func
presentWebView
(
url
:
String
)
}
class
MenuViewModel
:
ViewModelProtocol
{
class
MenuViewModel
:
NSObject
,
ViewModelProtocol
{
private
var
proVersionPurchaseInProgress
=
false
private
let
log
=
Logger
(
componentName
:
"MenuViewModel"
)
private
var
upgradeAlert
:
UIAlertController
?
...
...
@@ -57,6 +59,41 @@ class MenuViewModel: ViewModelProtocol {
}
}
public
func
viewAboutUs
()
{
self
.
delegate
?
.
presentWebView
(
url
:
ONE_WEATHER_ABOUT_US_URL
)
}
public
func
viewAdChoices
()
{
self
.
delegate
?
.
presentWebView
(
url
:
ONE_WEATHER_PRIVACY_OPTOUT_URL
)
}
public
func
viewFAQ
()
{
self
.
delegate
?
.
presentWebView
(
url
:
ONE_WEATHER_FAQ_URL
)
}
public
func
viewPrivacyPolicy
()
{
self
.
delegate
?
.
presentWebView
(
url
:
ONE_WEATHER_PRIVACY_URL
)
}
public
func
showDeviceId
()
{
guard
let
identifier
=
UIDevice
.
current
.
identifierForVendor
else
{
showAlert
(
"menu.deviceId.notAvailable.title"
.
localized
(),
message
:
"menu.deviceId.notAvailable.text"
.
localized
())
return
}
let
alert
=
UIAlertController
(
title
:
"menu.deviceId.title"
.
localized
(),
message
:
"menu.deviceId.text"
.
localized
()
+
"
\(
identifier
.
uuidString
)
"
,
preferredStyle
:
.
alert
)
let
copyAction
=
UIAlertAction
(
title
:
"general.copy"
.
localized
(),
style
:
.
default
)
{
(
_
)
in
UIPasteboard
.
general
.
string
=
identifier
.
uuidString
}
alert
.
addAction
(
copyAction
)
alert
.
addAction
(
.
init
(
title
:
"general.cancel"
.
localized
(),
style
:
.
cancel
))
self
.
delegate
?
.
viewControllerForPresentation
()
.
present
(
alert
,
animated
:
true
)
}
private
let
kOLAppMetricsCountKey
:
String
=
"count"
private
let
kOLAppMetricsDateKey
:
String
=
"date"
...
...
@@ -83,6 +120,101 @@ class MenuViewModel: ViewModelProtocol {
}
}
// MARK: - Help section
extension
MenuViewModel
{
private
func
helpRequestBodyString
()
->
String
{
var
str
=
String
()
str
.
append
(
"Weather Alerts Enabled:
\(
ConfigManager
.
shared
.
config
.
nwsAlertsViaMoEngageEnabled
)\n
"
)
let
isRegistered
=
UIApplication
.
shared
.
isRegisteredForRemoteNotifications
str
.
append
(
"Push Enabled:
\(
isRegistered
)\n
"
)
let
locs
=
LocationManager
.
shared
.
locations
for
loc
in
locs
{
let
myLoc
=
loc
.
deviceLocation
?
"MyLocation: "
:
""
let
alertStr
=
" FIPS
\(
loc
.
fipsCode
??
"no"
)
"
str
.
append
(
"
\(
myLoc
)
"
)
str
.
append
(
loc
.
nameForDisplay
)
str
.
append
(
" (
\(
(
loc
.
nickname
??
loc
.
cityName
)
??
""
)
)"
)
if
let
coordinates
=
loc
.
coordinates
{
str
.
append
(
String
(
format
:
" @%.5f,%.5f"
,
coordinates
.
latitude
,
coordinates
.
longitude
))
}
else
{
str
.
append
(
" no coordinates"
)
}
str
.
append
(
alertStr
)
str
.
append
(
"
\n
"
)
}
str
.
append
(
"
\n
--add your comments below--"
.
localized
)
return
str
}
public
func
showHelp
()
{
if
!
MFMailComposeViewController
.
canSendMail
()
{
let
alertView
=
UIAlertController
(
title
:
nil
,
message
:
"menu.help.unableToSendEmail.text"
.
localized
(),
preferredStyle
:
.
alert
)
alertView
.
addAction
(
UIAlertAction
(
title
:
"general.ok"
.
localized
(),
style
:
.
default
,
handler
:
nil
))
self
.
viewControllerForPresentation
()
.
present
(
alertView
,
animated
:
true
,
completion
:
nil
)
return
}
var
emailSubject
=
""
let
emailBody
=
helpRequestBodyString
()
var
emailRecipients
=
[
String
]()
var
deviceToken
=
""
emailSubject
=
"1Weather iOS Support Request"
emailRecipients
=
[
"oneweather_ios@onelouder.zendesk.com"
]
#if DEBUG
//TODO: REMOVE THIS'
emailRecipients
=
[
"rezonpk@yandex.ru"
]
#warning("THIS IS A DEBUG-ONLY PIECE OF CODE! Not even temporary! Remove before making a production build.")
#else
#error("THIS IS A DEBUG-ONLY PIECE OF CODE! Not even temporary! Remove before making a production build.")
#endif
if
let
lastUsedToken
=
PushNotificationsManager
.
shared
.
lastKnownPushToken
{
deviceToken
=
"
\n
Push Token:
\(
lastUsedToken
)
"
}
let
deviceName
=
UIDevice
.
current
.
modelName
let
version
=
Bundle
.
main
.
object
(
forInfoDictionaryKey
:
"CFBundleShortVersionString"
)
!
let
build
=
Bundle
.
main
.
object
(
forInfoDictionaryKey
:
"CFBundleVersion"
)
!
let
systemVersion
=
UIDevice
.
current
.
systemVersion
let
isPro
=
isAppPro
()
?
"Yes"
:
"No"
let
installedDate
=
"Unknown"
let
deviceInfo
=
"Version:
\(
version
)
-
\(
build
)\n
Device:
\(
deviceName
)\n
OS:
\(
systemVersion
)\n
Pro:
\(
isPro
)
\n
Installed:
\(
installedDate
)
\(
deviceToken
)
"
let
mc
:
MFMailComposeViewController
=
MFMailComposeViewController
()
mc
.
mailComposeDelegate
=
self
mc
.
modalPresentationStyle
=
.
formSheet
mc
.
setSubject
(
emailSubject
)
mc
.
setMessageBody
(
"
\(
deviceInfo
)
\n\n\(
emailBody
)
"
,
isHTML
:
false
)
mc
.
setToRecipients
(
emailRecipients
)
self
.
viewControllerForPresentation
()
.
present
(
mc
,
animated
:
true
,
completion
:
nil
)
}
}
extension
MenuViewModel
:
MFMailComposeViewControllerDelegate
{
public
func
mailComposeController
(
_
controller
:
MFMailComposeViewController
,
didFinishWith
result
:
MFMailComposeResult
,
error
:
Error
?)
{
switch
result
.
rawValue
{
case
MFMailComposeResult
.
cancelled
.
rawValue
:
log
.
debug
(
"Mail cancelled"
)
case
MFMailComposeResult
.
saved
.
rawValue
:
log
.
debug
(
"Mail saved"
)
case
MFMailComposeResult
.
sent
.
rawValue
:
log
.
info
(
"Mail sent"
)
case
MFMailComposeResult
.
failed
.
rawValue
:
log
.
error
(
"Mail sent failure:
\(
error
!.
localizedDescription
)
"
)
default
:
break
}
viewControllerForPresentation
()
.
dismiss
(
animated
:
true
,
completion
:
nil
)
}
}
extension
MenuViewModel
:
OLInAppStoreManagerDelegate
{
func
inAppStoreManager
(
_
inAppStoreManager
:
OLInAppStoreManager
,
purchaseCompletedForProductId
productId
:
String
)
{
onMain
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment