When you have a need to serve up files using http. You can do so with http-server
do this with npx http-server
.
PHP Ini File
Sometimes when you are using php you need to change some of the settings, this can be done by using the ini file.
Before you change anything in the ini file you should check the phpinfo. This can be done by creating a file containing <?php phpinfo(); ?>
and then navigating to the path for that file in a browser.
Once you have confirmed where the php ini file is, make your changes. To apply these changes you will have to restart apache. The code to do this depends on which platform you are running. One of the common ones can be done by systemctl restart apache2
. Hope this helps someone.
Code Style Tips
When you write if/else statements please put your else block on a new line not on the same line. The following doesn’t work with certain editor for code block collapsing.
if(x==1){
console.log("Blah");
} else {
console.log("bah");
}
Do the following instead.
if (x == 1)
{
console.log("Blah");
}
else
{
console.log("bah");
}
OR
if (x == 1) {
console.log("Blah");
}
else {
console.log("bah");
}
The second way allows those of us who use code collapse features inside of editors to collapse each part of the if/else. Thanks.
Slide Out Menu for iOS using SwiftUI
This week I’ve been working on prototyping a slide out menu, or as most people know it as the hamburger menu. This is a very useful navigation system for apps once the scale past 5 “systems” or tabs.
This system has to wrap the main content view inside of a wrapper view in order to handle the requirements of the system.
The requirements of the system are as follows
- It must use a navigation view to host a toolbar button that will allow the user to open the side menu.
- The side menu must contain a list, that the entire width of can be tapped on causing the content view to change to the newly assigned view, and closes the side menu.
- The side menu must be able to open and close using swipe gestures.
- When closed, swipe from left to right must open the side menu.
- When open, swipe from right to left must close the side menu.
- All other swipe gestures must be ignored.
- Tapping outside of the slide out menu must also close the menu.
Before we get too into the details we need a couple of things in the system to handle data storage and management. First we need a Observable Object to store the content view inside of.
class NavigationCoordinator: ObservableObject {
fileprivate var screen: AnyView = AnyView(EmptyView())
func show<V: View>(_ view: V) {
screen = AnyView(view)
}
}
The next thing we need is an enum for the swipe gesture directions. Since we only care about left and right those are the only ones I’ve included.
enum DragDirection {
case left
case right
case none
}
Now to get onto the creating of the actual views, we have to have a Side Menu. This is effectively just the container for the Slide Out navigation and animation.
struct SideMenu: View {
let width: CGFloat
let isOpen: Bool
let menuClose: () -> Void
let navigationCoordinator: NavigationCoordinator
var body: some View {
ZStack {
// Code here
GeometryReader { _ in
EmptyView()
}
.background(Color.gray.opacity(0.3))
.opacity(self.isOpen ? 1.0 : 0.0)
.animation(Animation.easeIn.delay(0.25))
.onTapGesture {
self.menuClose()
}
HStack {
MenuContent(navigationCoordinator: navigationCoordinator, menuClose: menuClose)
.frame(width: self.width)
.background(Color.white)
.offset(x: self.isOpen ? 0 : -self.width)
.animation(.default)
Spacer()
}
}
}
}
Next up is the content of the Slide Out Menu. Basically it’s just a list with some changes to make it look right in this context and to trigger the navigation on tap.
struct MenuContent: View {
let navigationCoordinator: NavigationCoordinator
let menuClose: () -> Void
var body: some View {
List {
ZStack {
VStack(alignment: .leading) {
HStack {
Text("My Profile")
Spacer()
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.contentShape(Rectangle())
.listRowBackground(Color.red)
.frame(maxWidth: .infinity)
.onTapGesture {
print("My Profile")
navigationCoordinator.show(Text("My Profile"))
menuClose()
}
ZStack {
VStack(alignment: .leading) {
HStack {
Text("Posts")
Spacer()
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.contentShape(Rectangle())
.listRowBackground(Color.teal)
.frame(maxWidth: .infinity)
.onTapGesture {
print("Posts")
navigationCoordinator.show(Text("Posts"))
menuClose()
}
ZStack {
VStack(alignment: .leading) {
HStack {
Text("Logout")
Spacer()
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.contentShape(Rectangle())
.listRowBackground(Color.indigo)
.frame(maxWidth: .infinity)
.onTapGesture {
print("Logout")
navigationCoordinator.show(Text("Logout"))
menuClose()
}
} // end list
}
}
Now onto the last big piece of this puzzle. This is the actual Content View, or in this case the main view of the application. This is where we handle the gestures and the navigation view.
struct ContentView: View {
@State var coordinator: NavigationCoordinator = NavigationCoordinator()
public init(@ViewBuilder content: () -> AnyView) {
coordinator.show(content())
}
public init() {
coordinator.show(EmptyView())
}
@State var menuOpen: Bool = false
var body: some View {
ZStack {
NavigationView {
HStack {
coordinator.screen
}
.navigationTitle("Add Location")
.navigationViewStyle(.automatic)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
openMenu()
}) {
Image(systemName: "line.3.horizontal")
}
}
} // end toolbar
}
.navigationViewStyle(.stack)
SideMenu(
width: 270,
isOpen: menuOpen,
menuClose: openMenu,
navigationCoordinator: coordinator)
}
.gesture(
DragGesture(minimumDistance: 60)
.onEnded { drag in
// TODO: fix the gestures that are supposed to be ignored.
let direction = drag.predictedEndLocation.x > drag.startLocation.x ? DragDirection.right : DragDirection.left
switch direction {
case .left:
self.menuOpen = false
case .right:
self.menuOpen = true
case .none:
break
}
}
) // end gesture
}
func openMenu() {
self.menuOpen.toggle()
}
}
Hope someone finds this useful and helps them build some awesome applications.
Navigation View Constraints
If you are using Swift UI and you get an error based around the constraints, you might be able to fix it by putting this line at the end of your navigation view.
.navigationViewStyle(.stack)
Dokku / NGINX not passing headers
Sometimes you just have to do a workaround when systems aren’t doing what they are supposed to, I have been building this API proxy for Weather Driver. Dokku / NGINX wasn’t passing the proper headers to my server, so I had to do a workaround.
The work around I came up with was to pass all the values in as part of the Request body. I still would like to figure out what the initial problem was caused by. If I come up with a full solution I will post back here about it.
Converting a callback function to async await in Swift
Occasionally you will need to convert a callback based function to an async/await function. One example of this is below, calculating a map route appears to be only available as a callback based one. Below is an example of how to convert it to an async function. This code is actually used in Weather Driver.
func calculateSubRoute(route: MKRoute, step: MKRoute.Step) async throws -> MKDirections.Response? {
return try await withCheckedThrowingContinuation { continuation in
let request = MKDirections.Request()
request.source = MKMapItem(placemark: MKPlacemark(coordinate: route.steps.first!.polyline.coordinate))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: step.polyline.coordinate))
request.requestsAlternateRoutes = true
request.transportType = .automobile
let directions = MKDirections(request: request)
directions.calculate() { response, error in
if error != nil {
print(error)
continuation.resume(throwing: error!)
return
}
continuation.resume(returning: response)
}
}
}
Do you know the difference between echo and print in PHP?
There isn’t very many differences they both can be used to output to the page, however print also returns a 1.
How do you get the JSON body in PHP?
$_POST
doesn’t always get you what you need. If you are passing in JSON as the body of a request, you can’t get it using $_POST. You will have to use file_get_contents('php://input');
. I found this to be extremely annoying and not well documented.
How to give good constructive feedback?
When giving feedback here is are some good rules to follow.
- Always have something positive to say even if you are giving bad feedback.
- Give good clear things that they can improve. Be clear about what you are suggesting.
- Don’t make it sound like they have to do the improvements.
- Give them the why to do the suggestions.
- Don’t tell them you won’t use their product until they add this or that feature.
- Provide all the information you can, including screenshots with annotations.