IOS high imitation kitchen (Objective-C)

Preface

The open source project to explain some of the common features of the App interface and the realization of the idea of building, suitable for novice.

Why the kitchen?

Under the kitchen: a collection of tools, community and platform electricity supplier attributes of the family food entrance. A great platform, App interface is also very good!

About the project (Github address at the end of the article)

  • Development environment: Xcode 7.2, language: Objective-C
  • The tools used: Charles capture tool
  • Degree of imitation: just as an exercise project, in addition to the interface without interface, as well as some small details are not adjusted, most of the other major functions are achieved. Other parts of the children can try to achieve their own ~!
  • Just started writing when the control is written in pure code, and later found too time-consuming to switch to Xib
  • If there is no reasonable code (such as: named), please forgive me, learning to achieve a good idea, please do not learn the code.
  • This open source project is suitable for beginners, the basic layout of the interface and business logic have, read this basic will also write a simple App
  • Note: because there was a special preference for block so a protocol code does not… Is novice, mainly to achieve the main idea! Hope you can help!

Preview effect

IOS high imitation kitchen (Objective-C)
home.Gif
IOS high imitation kitchen (Objective-C)
focus on dynamic.Gif
IOS high imitation kitchen (Objective-C)
menu.Gif
IOS high imitation kitchen (Objective-C)
posts and works.Gif
IOS high imitation kitchen (Objective-C)
commodity interface.Gif
IOS high imitation kitchen (Objective-C)
commodity classification selection.Gif
IOS high imitation kitchen (Objective-C)
commodity interface – image display animation.Gif
IOS high imitation kitchen (Objective-C)
shopping cart.Gif
IOS high imitation kitchen (Objective-C)
upload works.Gif
IOS high imitation kitchen (Objective-C)
receiving address.Gif
IOS high imitation kitchen (Objective-C)
search interface.Gif
IOS high imitation kitchen (Objective-C)
recipe – create and delete.Gif

A home page

IOS high imitation kitchen (Objective-C)
home.Png
layout
  • As shown in the home page tableView can get
  • Date heading sectionHeader
  • The following is the cell, the kitchen back to the data in the cell there are 6 kinds of templates, through the custom cell, according to different templates show different effects, it is not easy to describe
Thinking:

At the top of the navigation part of the event, through the control of each control tag, and then define the corresponding enumeration variables, through the closure (Block) to the event to the controller, the controller to determine the enumeration value can be.


1 jump interface controller

A menu

layout
  • The entire interface is a UIViewController, put a tableView, and then add the bottom of the collection, throw into the basket custom view
  • Materials, practices, tips, are added to the menu of these four titles is sectionHeader, which corresponds to a set of content, each group can be customized cell
IOS high imitation kitchen (Objective-C)
Recipes – Header.png
IOS high imitation kitchen (Objective-C)
Cookbook – works show.Png
  • The works show: here the implementation method with the above materials, practices… As independent as a group, only one in the cell group, cell contentView from top to bottom: add a number of works Label, CollectionView, Button all the works show works can slide left collectionView gesture will load the data, release more works
    here. Through the proxy implementation method of scrollView, to determine whether the value of contentOffset reaches a predetermined value, that is to call block, then send the network controller request load more data, you can refresh the interface. (here I just implemented a demand and did not further optimize the adjustment)
IOS high imitation kitchen (Objective-C)
Cookbook – bottom.Png
  • Layout:
    figure, the bottom of the menu can also be added sectionFooter,
    , although the kitchen is almost no border (there are split lines), but careful analysis is still very good division of the button

II works

IOS high imitation kitchen (Objective-C)
works.Png
layout
  • Because of the concern of the dynamic, buy buy buy interface with this almost, you need to reuse the content of the interface, so the entire interface is only one cell tableView
  • This is a picture of the carousel, add the following controls can be described Label and user comments, Label is the height of the contents of the decision, the only need to add a labelHeight property in the model, then calculate the height in the internal controls can be directly returned to the. The control part according to the different effect of different display interface, is divided into several parts, and then added to the cell a type attribute (enumeration type), created by the time to tell cell which belong to a type, and then type can be adjusted according to the different.

2 navigation

Pay attention to the dynamic

IOS high imitation kitchen (Objective-C)
focus on dynamic.Gif
layout
  • The entire interface on a tableView, a dynamic interface for the work of the cell
Problems encountered
  • The picture is influenced by the carousel reuse mechanism of tableViewCell, leading to confusion (point like button state is returned by the server data, I am not here simulated)
    solution: add imageViewCurrentLocationArray array attribute a record for rolling picture carousel position in the controller to achieve scrollView proxy method in picture carousel device the final contentOffset.x displacement monitoring records, after the closure, stop rolling / proxy location data transmitted to the controller, the controller will add to the position data of the array to record, this method should also apply to other problems caused by cell multiplex mechanism data show that (for array operations should be taken into account: on the drop-down refresh. Load more data and other information, see detailed code Engineering) wpap6030 01br as to which agent method to achieve the most reasonable, depending on the actual needs of the business and the effect of the interface, the following textField proxy is also true
ScrollView contentOffset.x / / stop recording after rolling - (void) scrollViewDidEndDecelerating: (UIScrollView * scrollView) {! Self.imageViewDidScrolledBlock? Self.imageViewDidScrolledBlock (scrollView.contentOffset.x);}
  • Finally, add a picture carousel attribute interface, receiving position data, and then set the picture in the constructor of the carousel is contentOffset – (void) setImageViewCurrentLocation: (CGFloat imageViewCurrentLocation) {_imageViewCurrentLocation = imageViewCurrentLocation; / / collectionView restore display scroll position [self.collectionView setContentOffset:CGPointMake (imageViewCurrentLocation, 0); / / pageLabel if (subscript restored self.pageLabel.hidden! & & self.imageArray.count) {NSInteger currentIndex = imageViewCurrentLocation / self.collectionView.frame.size.width + 1; self.pageLabel.text = “%zd/%zd” [NSString stringWithFormat:@, currentIndex, self.imageArray.count];}}

Three meals

IOS high imitation kitchen (Objective-C)
works.Png
layout
  • As shown in the figure, the entire controller is ViewController, the CollectionView and upload button to add to the viewController.view, relatively simple
  • The title of the navigation bar is a custom view, and then self.navigationItem.titleView = view;

This interface is known as “always die”, if you want to see the effect of your shoes can re capture


3 function interface

Sketch of the menu (the hardest item of the entire project)

IOS high imitation kitchen (Objective-C)
recipe creation – upper part.Png
IOS high imitation kitchen (Objective-C)
recipe creation – lower part.Png
layout

As shown in the figure, you need to pay attention to is: because this interface is the operation of the local data, so to be based on the data at any time to determine whether the change control display, how to display

thinking
  • Because it is a function of the interface to create and draft, so the operation is the local data, I wrote a recipe for the draft data tools category, used to add and delete changes, very convenient
  • Upload photos:
    click ActionSheet to allow users to select a camera, or photo album, and then through the proxy method – UIImagePickerController imagePickerController:didFinishPickingMediaWithInfo: can select photos because the top with a practice of upload pictures of the demand, if those who need to set the picture do not judge, will lead to the data display in the confusion, by proxy method in judging the caller agent you can solve the picture.
- (void) imagePickerController: (UIImagePickerController *) picker didFinishPickingMediaWithInfo: (NSDictionary< id> NSString *, info *) {/ / if is at the top of if (picker = = self.headerPicker) {self.createRecipe.image info[= UIImagePickerControllerEditedImage];} / / if else if steps (picker = = self.instructPicker) {self.instructionArray[self.setImageIndex].image} = info[UIImagePickerControllerEditedImage]; [self.tableView reloadData]; [picker dismissViewControllerAnimated:YES completion:^{[self updateDarft] / / select update local data after the completion of}];};
IOS high imitation kitchen (Objective-C)
draft interface – practice.Gif
  • Action steps: click the add steps to insert a row position corresponding to the tableView step cell, and an empty data approach the data into the corresponding position in the model of the data array, if you do not add it, click the edit data will lead to collapse because of cross-border
Add a click callback / / instructionFooter.addInstructionBlock = ^{/ / add an empty [weakSelf.instructionArray addObject:[[XCFCreateInstruction alloc] init]] local data; NSInteger row = weakSelf.instructionArray.count - 1; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:1] cell [weakSelf.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; / / insert;};
  • Click the adjustment step, tableView into the corresponding state of execution after the callback, [self.tableView setEditing:YES animated:YES]; here, need to pay attention to the problem: tableView only practice this group cell to enter edit mode in the -tableView: canMoveRowAtIndexPath: proxy method the judge can set the cell moving target position, even if the other group cannot enter edit mode, but the practice steps cell still can move into it, so it is necessary to set: if more than the practice steps of the section, no matter how to move, eventually returned to practice after the adjustment step section move cell, also need the corresponding practice step position synchronous data
/ / if not step back to the corresponding position - array (NSIndexPath *) tableView: (* UITableView) tableView targetIndexPathForMoveFromRowAtIndexPath: (NSIndexPath * sourceIndexPath) toProposedIndexPath: (NSIndexPath * proposedDestinationIndexPath) {NSIndexPath *finalIndexPath; / / if you drag to the zeroth group, then let go into the first group of zeroth if (proposedDestinationIndexPath.section = = 0) {finalIndexPath = [NSIndexPath indexPathForRow:0 inSection:1] if you drag to first;} / / group, let go that are inserted into the target position else if (proposedDestinationIndexPath.section = = 1) {finalIndexPath = proposedDestinationIndexPath;} / / if you drag to the second group, then let go into the first group of the last else if (propo SedDestinationIndexPath.section = = 2) {finalIndexPath} = [NSIndexPath indexPathForRow:self.instructionArray.count-1 inSection:1]; return finalIndexPath;}
IOS high imitation kitchen (Objective-C)
draft interface – material.Gif
  • Material:
    principle and practice steps are roughly the same, but the materials used in the editor is a new XCFIngredientEditController controller, with or without materials, click into the controller, then add an interface in XCFIngredientEditController, the data collection materials already exists, if the data is empty, the default will add two sample cell if that is not empty, it shows the existing data, so as to achieve the effect of add, edit or save the completed editing, pop to create the menu controller, and execute the callback return material data edited, you can refresh the interface
  • Because the official effect is: as long as the operation of the data, even if you do not click save, it will save the data, so I updated the data in each of the local data [self updateDarft];

Search II

IOS high imitation kitchen (Objective-C)
search interface.Gif
IOS high imitation kitchen (Objective-C)
search interface.Png
layout
  • Enter the search controller, to determine whether the local data has been searched keywords, there is no load, there is no show zeroth groups of cell
  • Enter the text, the use of the notification listener UITextFieldTextDidChangedNotification, and then through the closure of the contents of the text to the textField controller, while the time to refresh the tableView
  • Popular search keywords at the bottom of the network data is loaded, a palace
thinking
  • Because there is no interface, I encapsulate a single instance of the local class, save the search keywords, and provide data manipulation methods
  • Search: whether the traversal in the local data already exists in the key words, there will be new and delete old keywords, interspersed with keywords to zeroth; if it does not exist can be inserted directly into the zeroth (see detailed code Engineering)

Upload works

IOS high imitation kitchen (Objective-C)
upload works.Gif
layout

A tableHeaderView only tableViewController get, the official App in the picture, the label will be added animation, I did not achieve here, probably in the control of the frame value to add animation to

thinking
  • Local tool class, do not need to be persistent data, the data can be completed by callback
  • Need to pay attention to is: to deal with the picture, the label length display and line feed

Two, bazaar

1 commodities

IOS high imitation kitchen (Objective-C)
commodity interface.Png
layout
  • This part of my implementation method is: all as a tableHeaderView, and then divided into 3 parts, control the layout can be
  • Note: preferential price (red border button), shop discount (Orange), the server returns the string type data, here I will show preferential information to button (also Label), because the data is dynamic, so the maximum width can be calculated through the string, and then add the target length, different size you can set each button
IOS high imitation kitchen (Objective-C)
commodity interface.Gif
IOS high imitation kitchen (Objective-C)
commodity interface – Evaluation.Gif
thinking
  • The controller is UIViewController, the above commodity information display part is tableView, the graphic details of the interface is a UIView (UIView on a similar navigation label view, following CollectionView, CollectionView cell tableView, set up the internal added) corresponding to frame.
  • Continue to drag, view the graphic details:
    scrollView agent method to achieve this through contentOffset.y, determine whether the value reaches a predetermined value, the official effect is: don’t wait to let go, namely commodity display tableView and view graphic details and displacement of animation, and commodity display, tableView.hidden = YES; to achieve animation switching interface effect. By the graphic details of the goods back to the show is also achieved through proxy
/ / drag up to a certain extent, switch to the graphic details of the interface (void) - scrollViewDidScroll: (UIScrollView * scrollView) {/ / the predetermined value is 100 if (scrollView.contentOffset.y > self.tableView.contentSize.height - self.tableView.frame.size.height + 100) {/ / self.tableView.hidden = YES commodity information hiding; / / [UIView animateWithDuration:0.5 animations:^{self.tableView.transform = CGAffineTransformMakeTranslation animation (0 - (self.view.bounds.size.height-44-64)); self.imageTextView.transform = CGAffineTransformMakeTranslation (0 - (self.view.bounds.size.height-44));} completion:^ (BOOL finished) {[UILabel showStats:@ "does not solve the problem of webView causes a memory leak problem" at View:self.view];}];}}
  • Evaluation of CollectionView gestures sliding switch controller:
    is also the realization of the scrollView proxy method, through the callback switch controller
  • Slide Show / evaluation interface:
    official effect is: two tableView overlap, click on the tableView.hidden button to set the corresponding navigation bar

2 shopping cart

IOS high imitation kitchen (Objective-C)
shopping cart.Gif
layout
  • The entire controller is UIViewController, self.view add tableView with the bottom of the settlement view
  • The same store of goods as a set of cell, shop named sectionHeader
Train of thought (I set the empty cart to reload the local data)
  • The official is to receive the data through the server to display the contents of the shopping cart, because there is no interface so I built a new single example class, save the cart data, and provide data manipulation
  • Business logic: to add a XCFCartItemState enumeration of each product type attributes, records are selected, click the selected goods button callback, the controller to change the local data. Check the state and select shops, by traversing the local data corresponding to store all the goods or goods are all selected, then click refresh callback interface on the commodity can achieve real-time change the state the effect of commodity purchase quantity:
    in the internal implementation of the cell textField proxy method -textFieldShouldEndEditing: monitor the purchase quantity, edited by transitive closure the number of purchase to the controller, the controller changes the local data and refresh the interface cell.itemNumberChangeBlock ^ (NSUInteger = number) {/ / / / get the number of callback to modify product of the latest data, and then modify the number / / if you don’t get the latest data, in the quantity of the goods and click select Edit shop will lead to edit the selected state bug goods can not be synchronized NSArray *newShopArray = [XCFCartItemTool to TalItems][indexPath.section] XCFCartItem; *newItem = newShopArray[indexPath.row]; / / modify the data in a number of commodity value newItem.number = number; / / [XCFCartItemTool updateItemAtIndexPath:indexPath withItem:newItem] update local data; / / refresh interface [weakSelf.tableView reloadData];}; toggle edit / delete mode: closure callback
    simple interface to refresh, delete the words, according to the commodity status is selected, point select Delete, click to edit mode because the state is universal, so does not need to be calculated

3 confirmation of order

IOS high imitation kitchen (Objective-C)
order – upper part.Png
IOS high imitation kitchen (Objective-C)
order – lower part.Png
layout

As shown, the need to pay attention to is: if the results of the calculation of the shop discount price of 0, it will hide the shop discount

thinking
  • Directly to the shopping cart interface hook selected goods, through the calculation of the corresponding price figures can be displayed (freight only once)
  • Select the receiving address, access to the local storage of the receiving address data, there is a display, there is no hint to add
  • Because there is no money did not see the order, what kind of concessions, so did not do, but should be able to get the tableView

Three, community

IOS high imitation kitchen (Objective-C)
community.Gif
thinking
  • Select a comment cell, to get the comment author’s nickname, assignment in the end of the edit box, and then edit the control to determine whether or not the string, there is no delete, add
  • When in the edit box, as long as the last string for the “@”, will display the user tableView: using UITextViewTextDidChangeNotification and callback notification monitoring transfer last string to the controller, the controller judges display

Four, I

Because I don’t have any data, I don’t do the details

1 personal data

IOS high imitation kitchen (Objective-C)
personal interface.Gif

2 receiving address

IOS high imitation kitchen (Objective-C)
receiving address.Gif
thinking

Local data tool class, modify the contents of the closure of the callback controller to change the data, the internal processing of a good logical relationship can be


Five, animation

Picture display

IOS high imitation kitchen (Objective-C)
commodity interface – image display animation.Gif
thinking

The interface is a UIViewController interface, receive data, add a picture carousel view, executive animation appears after present (here I just realized the control effect, with the distribution of don’t do so carefully)
steps:

  1. Click picture
  2. The closure callback passes the frame value of the image in the current window, the subscript of the array in the image to the controller
  3. The controller passes the value to the picture display controller, and present
  4. The picture display controller receives the image data assigned to the picture carousel, and then create a imageView (as with animation), frame is set to a value from the interface is received, then the execution of imageView deformation animation
  5. The completion of the execution of the animation display picture carousel is removed from the imageView.
- (void) viewWillAppear: (BOOL) animated {[super viewWillAppear:animated]; UIButton *dismissButton = [[UIButton / / close button alloc] initWithFrame:CGRectMake (15, 15, 30, 30)]; [dismissButton setImage:[UIImage imageNamed:@ closeLandscape forState:UIControlStateNormal] [dismissButton addTarget:self]; action:@selector (close) forControlEvents:UIControlEventTouchUpInside]; dismissButton.alpha = 0; [self.view addSubview:dismissButton]; CGRect displayRect = / / picture carousel CGRectMake (0, XCFScreenHeight*0.5-175, XCFScreenWidth, 350); XCFImageShowView *showView = [[XCFImageShowView alloc] initWithFrame:displayRect]; / / set attribute showView.type = XCFShowViewTypeDetail; showView.imageArray = Self.imageArray; showView.currentIndex = self.imageIndex; showView.imageViewDidScrolledBlock = self.imageViewDidScrolledBlock; / / default first hide showView.hidden = YES; [self.view addSubview:showView]; / / add a temporary imageView CGRect [self.rectValue CGRectValue] animation rect = UIImageView; *imageView = [[UIImageView alloc] initWithFrame:rect]; XCFReviewPhoto *photo = self.imageArray[self.imageIndex]; [imageView sd_setImageWithURL:[NSURL URLWithString:photo.url]]; [self.view addSubview:imageView]; / / [UIView animateWithDuration:0.3 animations:^{= displayRect imageView.frame animation; completion:^ (BOOL finished) {} / / remove animation imageView [imageVie W removeFromSuperview]; / / showView.hidden display picture carousel = NO; [UIView animateWithDuration:0.3 animations:^{dismissButton.alpha = 1;}];}];}

Add goods to shopping cart

IOS high imitation kitchen (Objective-C)
commodity classification selection.Gif
IOS high imitation kitchen (Objective-C)
commodity classification view.png
layout
  • You can add a window, to achieve this requirement, you can also use the root window directly on the [UIApplication sharedApplication].keyWindow add a custom UIView, I am here with the latter.
  • The custom of a translucent UIView, according to the official animation, I am here with a tableView, only set the tableHeaderView (because lazy and do not use UIScrollView), the contents of tableHeaderView and UIView is a custom control, put not to say is very simple, but need to pay attention to is: control the logic relation between the types of goods is decided by the title of the button server data, so the tableView frame is not fixed because I can’t find the interface method can directly add a view counter in the middle, so I defined a XCFStepper counter, a small control is very simple, you can deal with the logical relationship
thinking
  • In the shopping cart to refresh the data method of local data tools in XCFCartItemTool (either delete or add, will refresh the data) notification custom, and transfer the quantity of the goods totalNumber / / add send notification, after the completion of use: shopping cart icon “NSNotificationCenter defaultCenter] postNotificationName:XCFCartItemTotalNumberDidChangedNotification object:nil userInfo:@{@ animation” goodsCount “: @ ([self totalNumber])}];
  • Shopping cart icon for the custom UIView, [[UIBarButtonItem alloc] initWithCustomView:cartIcon]; and then added to the navigation bar, inside the view XCFCartItemTotalNumberDidChangedNotification after receiving notice of the core animation can achieve the effect
- (void awakeFromNib) {/ / monitor "add items to the shopping cart" notice [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (cartItemTotalNumberDidChanged:) name:XCFCartItemTotalNumberDidChangedNotification object:nil]; NSUInteger count = [XCFCartItemTool totalNumber]; if (count) {/ / commodity to display the number of labels self.countButton.hidden = NO; [self.countButton setTitle:[NSString stringWithFormat:@%zd, count] forState:UIControlStateNormal];}} - (void cartItemTotalNumberDidChanged: (NSNotification * Note)) {self. CountButton.hidden NSDictionary = NO; *dict = note.userInfo; / / get the number of goods NSUInteger count = "goodsCount [dict[@ integerValue]"]; / / delay for animation (dispatch_time dispatch_after (DISPATCH_TIME_NOW (int64_t) (1 * NSEC_PER_SEC)), dispatch_get_main_queue ([UIView animateWithDuration:0.5 animations:^{), ^{/ shopping cart icon to perform zoom animation self.countButton.transform = CGAffineTransformMakeScale (1.5. 1.5); completion:^ (BOOL finished) {} / / to change the display of the number of goods [self.countButton setTitle:[NSString stringWithFormat:@%zd, count] forState:UIControlStateNormal]; / / [UIView anima icon size reduction TeWithDuration:0.5 animations:^{self.countButton.transform = CGAffineTransformMakeScale (1, 1);}];}];}});
  • Here I simulated the add effect: from the local data randomly taken a commodity if the commodity has only one type, directly added to the shopping cart if the goods are of various types (such as: 300g, 450g, 600g), with collision animation (I use pop Facebook framework) pop merchandise select the categories tableView, and commodity information behind view to zoom, set the category and quantity to be purchased after the implementation of core product images animation, and then remove the category view, execute add to cart the animation interface is relatively simple, just pay attention to small details, the animation sequence, and the corresponding add to shopping the car (or purchased) business logic / random add as commodity XCFCartItem *randomItem = [XCFCartItemTool randomItem]; XCFGoods *randomGoods = randomItem.goods; / / add to cart if (type = = BottomViewClickedAddToShoppingCart) {/ / if the goods are of various types, it allows the user to select a specific window to buy which type if (randomGoods.kinds.count > 1) {UIWindow *window = [UIApplication sharedApplication].keyWindow; [UIView animateWithDuration:0.3 animations:^{/ / narrow the current interface window.rootViewController.view.transform = CGAffineTransformMakeScale (0.9, 0.9);}]; according to the classification of goods view XCFKindsCategoryView / / *kindsView = “XCFKindsCategoryView alloc] initWithFrame:window.bounds]; / / view classification of pop-up type (shopping cart) kindsView.type = XCFKindsViewTypeCart; KindsView.item = randomItem; [window addSubview:kindsView]; / / confirm the purchase callback kindsView.confirmBlock (XCFCartItem = *item) ^ {/ / local shopping cart add data [XCFCartItemTool addItem:item] [UILabel showStats:[NSString stringWithFormat:@ commodity; add: /n%@, item.kind_name] atView:weakSelf.view];}; / / kindsView.cancelBlock / / ^{= cancel callback interface size [UIView animateWithDuration:0.3 animations:^{recovery window.rootViewController.view.transform = CGAffineTransformMakeScale (1, 1)}]; else;};} {/ / if there is only one commodity, directly into the shopping cart [XCFCartItemTool addItemRandomly:^ (NSString *goodsName) {[UILabel showStats:[NSString stringWithFormat:@ “were added: /n%@”, goodsName] atView:weakSelf.view];}];}}

Last words to say

  • The project is in accordance with the automatic layout of iPhone6s, other models may be biased, forgive me can achieve basically realized the market module interface is encrypted, so do not, but the visual is a simple CollectionView+ animation can fix the basket interface should be my ideas are so if not completed, follow-up will try to achieve the same effect, some very simple interface if I have time I really don’t want to write! Nothing, interested can try to achieve the process of children’s writing code to run ManoBoo godling harassing yourself here super thanks to ManoBoo! Also helped me solve two bug! There are thanks to Vigny’s great bear’s open source App, two predecessors on the interface to explain the ideas I benefited. Thanks for everything.

Github code download address

High imitation kitchen App open source slightly ~

  • If you are a novice, and my project to help you, please give me generous Star! The open source world so beautiful help indebted forever! If you don’t give me Star, don’t force it…
    IOS high imitation kitchen (Objective-C)
  • If you are God…
    IOS high imitation kitchen (Objective-C)

END