Skip to content

Commit

Permalink
added wishes/automatic requests
Browse files Browse the repository at this point in the history
  • Loading branch information
nedley committed Oct 2, 2019
1 parent 942ae07 commit c74c1e8
Show file tree
Hide file tree
Showing 22 changed files with 894 additions and 15 deletions.
70 changes: 63 additions & 7 deletions appdb.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions appdb/API/API+Wishes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// API+Wishes.swift
// appdb
//
// Created by ned on 07/07/2019.
// Copyright © 2019 ned. All rights reserved.
//

import Alamofire
import SwiftyJSON

extension API {

static func createPublishRequest(appStoreUrl: String, type: String = "ios", completion:@escaping (_ error: String?) -> Void) {
Alamofire.request(endpoint, parameters: ["action": Actions.createPublishRequest.rawValue, "url": appStoreUrl, "type": type], headers: headersWithCookie)
.responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
if !json["success"].boolValue {
completion(json["errors"][0].stringValue)
} else {
completion(nil)
}
case .failure(let error):
completion(error.localizedDescription)
}
}
}

static func getPublishRequests(includeAll: Bool, page: Int = 1, success:@escaping (_ items: [WishApp]) -> Void, fail:@escaping (_ error: String) -> Void) {
Alamofire.request(endpoint, parameters: ["action": Actions.getPublishRequests.rawValue, "type": "ios", "include_all": includeAll ? 1 : 0, "page": page], headers: headers)
.responseArray(keyPath: "data") { (response: DataResponse<[WishApp]>) in
switch response.result {
case .success(let results):
success(results)
case .failure(let error):
fail(error.localizedDescription)
}
}
}
}
2 changes: 2 additions & 0 deletions appdb/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ enum Actions: String {
case deleteIpa = "delete_ipa"
case addIpa = "add_ipa"
case analyzeIpa = "get_ipa_analyze_jobs"
case createPublishRequest = "create_publish_request"
case getPublishRequests = "get_publish_requests"
}

enum ConfigurationParameters: String {
Expand Down
67 changes: 67 additions & 0 deletions appdb/Models/WishApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// WishApp.swift
// appdb
//
// Created by ned on 07/07/2019.
// Copyright © 2019 ned. All rights reserved.
//

import ObjectMapper
import Localize_Swift

struct WishApp: Mappable {

init?(map: Map) { }

var id: String = ""
var trackid: String = ""
var version: String = ""
var image: String = ""
var name: String = ""
var requestersAmount: String = ""
var price: String = ""
var statusString: String = ""
var status: Status = .new
var statusChangedAt: String = ""
var bundleId: String = ""

enum Status: String {
case cracking, fulfilled, failed, new

// todo localize
var prettified: String {
switch self {
case .new: return "New".localized()
case .cracking: return "⚙︎ " + "Processing".localized()
case .failed: return "𐄂 " + "Failed".localized()
case .fulfilled: return "" + "Fulfilled".localized()
}
}
}

mutating func mapping(map: Map) {
id <- map["id"]
trackid <- map["trackid"]
version <- map["version"]
image <- map["image"]
name <- map["name"]
requestersAmount <- map["requesters_amount"]
price <- map["price"]
statusString <- map["status"]
statusChangedAt <- map["status_changed_at"]
bundleId <- map["bundle_id"]

name = name.decoded

price = price == "0.00" ? "Free".localized() : price

status = Status(rawValue: statusString) ?? .new

let date = statusChangedAt.unixToDate
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: Localize.currentLanguage())
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
statusChangedAt = dateFormatter.string(from: date)
}
}
26 changes: 26 additions & 0 deletions appdb/Other/Images.xcassets/wishes.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Untitled.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "[email protected]",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "[email protected]",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation
import UIKit

// An adaptive UIAlertController that can adapt to light and dark themes
// An adaptive UIAlertController (iOS >= 11 && iOS < 13) that can adapt to light and dark themes
// Source: https://stackoverflow.com/a/41780021

extension UIAlertController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class AskBundleBeforeUploadViewController: TableViewController {
["initialText": self.newBundleId, "callback": { [unowned self] (newBundleId: String) in
self.newBundleId = newBundleId
self.setUploadButtonEnabled()
}, "title": "New bundle id".localized(), "subtitle": "Tap to generate random".localized()] // todo localize
}, "title": "New bundle id".localized(), "subtitle": "Tap to generate random".localized()]
),
Row(text: "Overwrite file".localized(), accessory: .switchToggle(value: overwriteFile) { [unowned self] newValue in
self.overwriteFile = newValue
Expand Down
9 changes: 7 additions & 2 deletions appdb/Resources/• LoadingTableView/LoadingTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,16 @@ class LoadingTableView: UITableViewController {

setConstraints(.loading)

adMobAdjustContentInsetsIfNeeded()
// Wishes are presented modally so you don't need to set bottom insets
if !(self is NewWishes) && !(self is FulfilledWishes) {
adMobAdjustContentInsetsIfNeeded()
}

adChangeObservation = defaults.observe(.adBannerHeight) { [weak self] _ in
guard let self = self else { return }
self.adMobAdjustContentInsetsIfNeeded()
if !(self is NewWishes) && !(self is FulfilledWishes) {
self.adMobAdjustContentInsetsIfNeeded()
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions appdb/Startup/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ extension String {
case "NOT_READY": return "The request timed out".localized()
case "NOT_COMPATIBLE_WITH_DEVICE": return "Your device is not compatible with this app".localized()
case "REPORT_ALREADY_SUBMITTED": return "A report has already been submitted".localized()
case "ERROR_PRO_REQUIRED": return "Your device needs to be PRO in order to request paid apps to be uploaded automatically.".localized()
case "ERROR_PAID_APPS_REQUESTS_LIMIT_REACHED": return "Paid apps request limit reached. You can request up to 1 paid apps per week.".localized()
case "ERROR_REQUEST_APPLE_APP": return "This app can not be requested, it is native iOS/iPadOS/tvOS app.".localized()
case "ERROR_REQUEST_ONLY_IOS_APPS_SUPPORTED": return "Only iOS Apps From AppStore are supported in automatic requests.".localized()
case "ERROR_REQUEST_STATUS_CANT_BE_SET": return "This request status can't be set.".localized()
case "ERROR_SUCH_REQUEST_EXISTS": return "Such request already exists. But we have added you as requester as well.".localized()
case "ERROR_SUCH_VERSION_EXISTS_AND_LINKS_AVAILABLE": return "Such version is already on appdb and it has links available.".localized()
case "JSON could not be serialized because of error:\nThe data couldn’t be read because it isn’t in the correct format.": return "An error has occurred: malformed JSON".localized()
default: return self.localized()
}
Expand Down
24 changes: 24 additions & 0 deletions appdb/Tabs/Featured/Featured/Featured.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ class Featured: LoadingTableView, UIPopoverPresentationControllerDelegate {
navigationItem.leftBarButtonItem = categoriesButton
navigationItem.leftBarButtonItem?.isEnabled = false

// Add wishes button

let wishesButton = UIBarButtonItem(image: UIImage(named: "wishes"), style: .plain, target: self, action: #selector(self.openWishes))
navigationItem.rightBarButtonItem = wishesButton
navigationItem.rightBarButtonItem?.isEnabled = false

// Fix random separator margin issues
if #available(iOS 9, *) { tableView.cellLayoutMarginsFollowReadableWidth = false }

Expand All @@ -58,6 +64,9 @@ class Featured: LoadingTableView, UIPopoverPresentationControllerDelegate {

// Enable categories button
self.navigationItem.leftBarButtonItem?.isEnabled = true

// Enable wishes button
self.navigationItem.rightBarButtonItem?.isEnabled = true
})

// Wait for data to be fetched, reload tableView on completion
Expand Down Expand Up @@ -125,6 +134,9 @@ class Featured: LoadingTableView, UIPopoverPresentationControllerDelegate {

// Enable categories button
self.navigationItem.leftBarButtonItem?.isEnabled = true

// Enable wishes button
self.navigationItem.rightBarButtonItem?.isEnabled = true
})

for cell in self.cells.compactMap({$0 as? ItemCollection}) { cell.requestItems() }
Expand All @@ -150,6 +162,18 @@ class Featured: LoadingTableView, UIPopoverPresentationControllerDelegate {
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return state == .done ? cells[indexPath.row].height : 0
}

// Open wishes
@objc func openWishes(_ sender: AnyObject) {
let wishesController = Wishes()
if Global.isIpad {
let nav = DismissableModalNavController(rootViewController: wishesController)
nav.modalPresentationStyle = .formSheet
self.navigationController?.present(nav, animated: true)
} else {
self.navigationController?.present(UINavigationController(rootViewController: wishesController), animated: true)
}
}
}

////////////////////////////////
Expand Down
110 changes: 110 additions & 0 deletions appdb/Tabs/Featured/Wishes/Cells/WishAppCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// WishAppCell.swift
// appdb
//
// Created by ned on 26/07/2019.
// Copyright © 2019 ned. All rights reserved.
//

import UIKit
import Cartography

class WishAppCell: UITableViewCell {

var nameLabel: UILabel!
var infoLabel: UILabel!
var statusLabel: UILabel!
var icon: UIImageView!

func configure(with app: WishApp) {
nameLabel.text = app.name
infoLabel.text = "Price: %@".localizedFormat(app.price) + Global.bulletPoint + "Version: %@".localizedFormat(app.version)
if app.status == .new {
statusLabel.text = "\(app.requestersAmount)" + Global.bulletPoint + app.statusChangedAt
} else {
statusLabel.text = app.status.prettified + Global.bulletPoint + app.statusChangedAt
}
if let url = URL(string: app.image) {
icon.af_setImage(withURL: url, placeholderImage: #imageLiteral(resourceName: "placeholderIcon"),
filter: Global.roundedFilter(from: 80 ~~ 60),
imageTransition: .crossDissolve(0.2))
}
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: .default, reuseIdentifier: reuseIdentifier)

setup()
setConstraints()
}

private func setup() {

//UI
theme_backgroundColor = Color.veryVeryLightGray
setBackgroundColor(Color.veryVeryLightGray)
let bgColorView = UIView()
bgColorView.theme_backgroundColor = Color.cellSelectionColor
selectedBackgroundView = bgColorView
accessoryType = .disclosureIndicator

// Name
nameLabel = UILabel()
nameLabel.theme_textColor = Color.title
nameLabel.font = .systemFont(ofSize: 15 ~~ 14)
nameLabel.numberOfLines = 1
nameLabel.makeDynamicFont()

// Info Label
infoLabel = UILabel()
infoLabel.theme_textColor = Color.darkGray
infoLabel.font = .systemFont(ofSize: 13 ~~ 12)
infoLabel.numberOfLines = 1
infoLabel.makeDynamicFont()

// Status Label
statusLabel = UILabel()
statusLabel.theme_textColor = Color.darkGray
statusLabel.font = .systemFont(ofSize: 13 ~~ 12)
statusLabel.numberOfLines = 1
statusLabel.makeDynamicFont()

// Icon
icon = UIImageView()
icon.layer.borderWidth = 1 / UIScreen.main.scale
icon.layer.theme_borderColor = Color.borderCgColor

icon.layer.cornerRadius = Global.cornerRadius(from: (80 ~~ 60))

contentView.addSubview(nameLabel)
contentView.addSubview(infoLabel)
contentView.addSubview(statusLabel)
contentView.addSubview(icon)
}

// Set constraints
private func setConstraints() {
constrain(icon, nameLabel, infoLabel, statusLabel) { icon, name, info, status in
icon.width ~== (80 ~~ 60)
icon.height ~== icon.width
icon.leading ~== icon.superview!.layoutMarginsGuide.leading
icon.centerY ~== icon.superview!.centerY

name.leading ~== icon.trailing ~+ (15 ~~ 12)
name.trailing ~== name.superview!.trailing ~- Global.Size.margin.value
name.centerY ~== name.superview!.centerY ~- (22 ~~ 20)

info.top ~== name.bottom ~+ (5 ~~ 4)
info.leading ~== name.leading
info.trailing ~== name.trailing

status.leading ~== info.leading
status.trailing ~<= status.superview!.trailing ~- Global.Size.margin.value
status.top ~== info.bottom ~+ (5 ~~ 4)
}
}
}
Loading

0 comments on commit c74c1e8

Please sign in to comment.