Feature #1277

Add iPhone specific view

Added by Robert Cerny over 9 years ago. Updated over 4 years ago.

Status:ClosedStart date:2008-05-21
Priority:NormalDue date:
Assignee:-% Done:


Target version:-

mobile.css Magnifier (1.76 KB) Semyon Vyskubov, 2010-09-17 18:37

Related issues

Duplicated by Redmine - Feature #3317: API and iPhone app Closed 2009-05-07
Duplicates Redmine - Feature #883: Add suport for mobile devices (CSS) Closed 2008-03-17


#1 Updated by Tommy Jensen over 9 years ago


#2 Updated by Anonymous over 9 years ago

+1 from me too.

#3 Updated by Simpsom Boy over 9 years ago

Iphone seems to be too specific.
maybe a more generic mobile version?
or... both


#4 Updated by Anonymous over 9 years ago

I agree more general would be ideal, but I'm not sure how compatible all the other mobile browsers are with standards. All sites I've encountered currently written specifically for the iPhone will work in a normal desktop browser (well, I've tried Firefox and Apple's Safari with them). Are other browsers as compatible? Everything I've read so far points to most manufacturers bringing out much more capable mobile browsers similar to the iPhone's, so making a site that just uses standards rather than tailored towards a specific mobile browser would be ideal.

#5 Updated by Robert Cerny over 9 years ago

actually I believe that adding support for mobile devices can be done in two steps. First one is iPhone specific, which is relatively easy due a nature of RoR. The second, based on wap protocol is far more work. There is no standard for mobile devices other than iPhone and I'm not sure if Mobile Opera claims it's mobile version in User Agent...

#6 Updated by Maxim Krušina over 9 years ago

Hi there, I already created ticket #883, wher I want to add support generaly for all mobile devices. Original idea was to add support for Windows Mobile with IE or Opera, but adding support for other mobile devices like iPhone should be the same task.

We're already started working on mobile version, which should be CSS based, so in the best case code base will be same, only CSS stylesheet will be different. Our company is now finishing one very larg project, so I hope in one or two weeks we can dive into solution.

We already have both HW devices and SW emulators of Windows Mobile 5/6, but please, but we don't have iPhone... Can someone post link to some iPhone emulator, if it estists?

#7 Updated by Anonymous over 9 years ago

The iPhone SDK (and emulator) is available here: http://developer.apple.com/iphone/ But it only runs on Mac OS X, not Windows, and probably not necessary if you are just developing web-apps for the iPhone.

However, the iPhone browser is basically the same as Apple's desktop browser, Safari, available for Windows here http://www.apple.com/safari/ and documentation on how to develop web-based apps (and test them on Safari) is here http://developer.apple.com/webapps/ Registration is required but it is free.

#8 Updated by Anonymous over 9 years ago

I know nothing about web development, but having a quick look at the guidelines for iPhone web-apps says this:

Stick with standards when you design webpages for iPhone. Safari on iPhone shares the same Web Kit engine as Safari on the computer desktop. It supports all the latest modern web standards, including:
  • HTML 4.01
  • XHTML 1.0
  • CSS 2.1 and partial CSS3
  • ECMAScript 3 (JavaScript)
  • W3C DOM Level 2
  • AJAX technologies, including XMLHTTPRequest

#9 Updated by Robert Cerny over 9 years ago

There is another free iPhone simulator here: http://marketcircle.com/iphoney/

Basically, you can stick with Windows, just install Safari for Windows http://www.apple.com/safari and change the window size to 320px.

Rusell: The current Redmine 0.7 works great on iPhone, but the support could be better. For example the Sign-in link is very small while browsing on 320px device, and it's not possible to reach it without zooming. I posted some links above how to implement support for iPhone the right way and really think it's 1 afternoon work. You just need to add iUi framework to the project (it contains the right css, buttons etc.), improve controller to catch iPhone user agent and fiddle templates to support new css and designs.

#10 Updated by Maxim Krušina over 9 years ago

We really don't play WAP version. It's so much work, WAP is a lot different to classic HTML pages. Anyway, I guess that project managers who really want do business in mobile way already have some better phone/gadget mobile browsing.

Anyway there is some work on GUI, which will be same for both iPhone/WIndows Mobile/Opera ... there is need for some simplification of GUI, etc. so it will fit best on the small screen.

#11 Updated by Maxim Krušina over 9 years ago

Anyway, we have one Mac so I can chceck it in (almost) native OS.

#12 Updated by Chris Platts over 9 years ago

Just as a passing comment, there's a Develop menu in Safari on both Mac and Windows -- guide to enable it is here. Although 'desktop' Safari is essentially the same engine as that for the iPhone, the Develop menu will allow you to set its user-agent string to that of the iPhone's edition of the browser. I dare say there's also plenty of other options in the Develop menu which could assist in designing/debugging the CSS.

#13 Updated by Jim Mulholland almost 9 years ago

  • Assignee set to Jim Mulholland
  • % Done changed from 0 to 30

The Squeejee team is working on a prototype of a Redmine iPhone interface right now. We are hoping to have something to share next week.

#14 Updated by Stefaan Ellebaut almost 9 years ago

Hello Jim,
We are a month further now and I am really hoping you can tell us where we can find a beta version or at least share a status of this feature!

#15 Updated by Conrad S. almost 9 years ago

Would be very useful!

#16 Updated by Derek Montgomery over 8 years ago

Same here!

#17 Updated by Peter Edstrom over 8 years ago


#18 Updated by Jim Mulholland over 8 years ago

Hey guys. I sincerely apologize, but we have made very little progress on the Redmine iPhone app since I assigned this ticket to myself several months ago. I also do not see us getting a chance to work on it in the near future, either.

If any of you would like to take a crack at an iPhone version, please let me know and I can reassign the ticket.

#19 Updated by Henrik Mohr about 8 years ago

Jim Mulholland wrote:

If any of you would like to take a crack at an iPhone version, please let me know and I can reassign the ticket.

I can start working on an iPhone app (not web "skin" but real app) if noone has started yet?

#21 Updated by Michael Aye about 8 years ago

but at least for me, it's not in a good state yet. Can't connect to our redmine server (NSXMLParserErrorDomain error 76).
But at least there is a start.

#22 Updated by Thomas Stägemann about 8 years ago

hey, i'm the developer who released iRedmine.

You can contribute to the further development:

#23 Updated by Eric Davis about 8 years ago

Thomas Stägemann,

Thanks, iRedmine looks promising. I'm also getting some XML parse errors when I connect to my server. How would you like bug reports? (I know 0 about iPhone apps)

#24 Updated by Thomas Stägemann almost 8 years ago

A new version is coming very soon.

#25 Updated by Maxim Krušina almost 8 years ago

Wow, great news! I'm here to test in on our androids... any usable version somewhere? ;)

#26 Updated by Oleg Lozinskij over 7 years ago

great! just great!

do you plan a version for BlackBerry?

#27 Updated by Greg Thornton over 7 years ago

Now that we know the difference between iPhone apps, other mobile apps, and now "iPhone optimized" web apps, can anyone point to any actual efforts in the latter direction? Has anyone yet asked "iPad"?

#28 Updated by Anonymous over 7 years ago

Greg Thornton wrote:

Now that we know the difference between iPhone apps, other mobile apps, and now "iPhone optimized" web apps, can anyone point to any actual efforts in the latter direction? Has anyone yet asked "iPad"?

The normal website works well on the iPad so I don't see a need for an iPad version

#29 Updated by Terence Mill about 7 years ago


#30 Updated by Semyon Vyskubov about 7 years ago

Hi All!

Here is an attached mobile.css file that makes a nice and compact view of Redmine for iPhone. (It's not a commented properly, sorry)

I've made some template edits also:

/app/views/layouts/base.rhtml (include mobile.css for iPhone)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title><%=h html_title %></title>
<meta name="description" content="<%= Redmine::Info.app_name %>" />
<meta name="keywords" content="issue,bug,tracker" />
<%= stylesheet_link_tag 'application', :media => 'all' %>
<%= javascript_include_tag :defaults %>
<%= heads_for_wiki_formatter %>
<!--[if IE]>
    <style type="text/css">
      * html body{ width: expression( document.documentElement.clientWidth < 900 ? '900px' : '100%' ); }
      body {behavior: url(<%= stylesheet_path "csshover.htc" %>);}
<%= call_hook :view_layouts_base_html_head %>
<!-- page specific tags -->
<%= yield :header_tags -%>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0" />
<link media="only screen and (max-device-width: 480px)" href="http://knossos.ru/mobile.css" type="text/css" rel="stylesheet" />
<div id="wrapper">
<div id="top-menu">
    <div id="account">
        <%= render_menu :account_menu -%>
    <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}", :id => 'loggedas') if User.current.logged? %>
    <%= render_menu :top_menu -%>

<div id="header">
    <div id="quick-search">
        <% form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>
        <%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %>
        <%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project}, :accesskey => accesskey(:search) %>:
        <%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search) %>
        <% end %>
        <%= render_project_jump_box %>

    <h1><%= page_header_title %></h1>

    <% if display_main_menu?(@project) %>
    <div id="main-menu">
        <%= render_main_menu(@project) %>
    <% end %>

<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %>
    <div id="sidebar">        
        <%= yield :sidebar %>
        <%= call_hook :view_layouts_base_sidebar %>

    <div id="content">
                <%= render_flash_messages %>
        <%= yield %>
        <%= call_hook :view_layouts_base_content %>
                <div style="clear:both;"></div>

<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>

<div id="footer">
    Powered by <%= link_to Redmine::Info.app_name, Redmine::Info.url %> &copy; 2006-2010 Jean-Philippe Lang
<%= call_hook :view_layouts_base_body_bottom %>

/app/views/issues/_relations.rhtml (here some of relations tables cells are hidden)

<div class="contextual">
<% if authorize_for('issue_relations', 'new') %>
    <%= toggle_link l(:button_add), 'new-relation-form'%>
<% end %>


<% if @issue.relations.any? %>
<table width="100%">
<% @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation| %>
<td><%= l(relation.label_for(@issue)) %> <%= "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)})" if relation.delay && relation.delay != 0 %>
    <%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %>
    <%= link_to_issue relation.other_issue(@issue) %>
<td class="mobile_hide"><%= relation.other_issue(@issue).status.name %></td>
<td class="mobile_hide"><%= format_date(relation.other_issue(@issue).start_date) %></td>
<td class="mobile_hide"><%= format_date(relation.other_issue(@issue).due_date) %></td>
<td class="mobile_hide"><%= link_to_remote(image_tag('delete.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :issue_id => @issue, :id => relation},                                              
                                                  :method => :post
                                                }, :title => l(:label_relation_delete)) if authorize_for('issue_relations', 'destroy') %></td>
<% end %>
<% end %>

<% remote_form_for(:relation, @relation, 
                 :url => {:controller => 'issue_relations', :action => 'new', :issue_id => @issue},
                 :method => :post,
                 :html => {:id => 'new-relation-form', :style => (@relation ? '' : 'display: none;')}) do |f| %>
<%= render :partial => 'issue_relations/form', :locals => {:f => f}%>
<% end %>

/app/views/_edit.rhtml (attach file field are hidden)

<% labelled_tabular_form_for :issue, @issue,
                             :url => {:action => 'edit', :id => @issue},
                             :html => {:id => 'issue-form',
                                       :class => nil,
                                       :multipart => true} do |f| %>
    <%= error_messages_for 'issue' %>
    <%= error_messages_for 'time_entry' %>
    <div class="box">
    <% if @edit_allowed || !@allowed_statuses.empty? %>
        <fieldset class="tabular"><legend><%= l(:label_change_properties) %>
        <% if !@issue.new_record? && !@issue.errors.any? && @edit_allowed %>
        <small>(<%= link_to l(:label_more), {}, :onclick => 'Effect.toggle("issue_descr_fields", "appear", {duration:0.3}); return false;' %>)</small>
        <% end %>
        <%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %>
    <% end %>
    <% if authorize_for('timelog', 'edit') %>
        <fieldset class="tabular"><legend><%= l(:button_log_time) %></legend>
        <% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %>
        <div class="splitcontentleft">
        <p><%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %></p>
        <div class="splitcontentright">
        <p><%= time_entry.select :activity_id, activity_collection_for_select_options %></p>
        <p><%= time_entry.text_field :comments, :size => 60 %></p>
        <% @time_entry.custom_field_values.each do |value| %>
            <p><%= custom_field_tag_with_label :time_entry, value %></p>
        <% end %>
        <% end %>
    <% end %>

    <fieldset><legend><%= l(:field_notes) %></legend>
    <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
    <%= wikitoolbar_for 'notes' %>
    <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %>

    <p class="mobile_hide"><%=l(:label_attachment_plural)%><br /><%= render :partial => 'attachments/form' %></p>

    <%= f.hidden_field :lock_version %>
    <%= submit_tag l(:button_submit) %>
    <%= link_to_remote l(:label_preview), 
                       { :url => { :controller => 'issues', :action => 'preview', :project_id => @project, :id => @issue },
                         :method => 'post',
                         :update => 'preview',
                         :with => 'Form.serialize("issue-form")',
                         :complete => "Element.scrollTo('preview')" 
                       }, :accesskey => accesskey(:preview) %>
<% end %>

<div id="preview" class="wiki"></div>

/app/views/show.rhtml (proper divide of issue's details table)

<%= render :partial => 'action_menu' %>

<h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>

<div class="<%= @issue.css_classes %> details">
        <%= avatar(@issue.author, :size => "50") %>
        <h3><%=h @issue.subject %></h3>
        <p class="author">
        <%= authoring @issue.created_on, @issue.author %>.
        <% if @issue.created_on != @issue.updated_on %>
        <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
        <% end %>

<div class="splitcontentleft">
<table class="attributes">
    <th class="status"><%=l(:field_status)%>:</th><td class="status"><%= @issue.status.name %></td>
    <th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= @issue.priority.name %></td>
    <th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
    <th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h @issue.category ? @issue.category.name : "-" %></td>
    <th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
<%= render_custom_fields_rows(@issue) %>

<div class="splitcontentright">
<table class="attributes">
    <th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td>
    <th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td>
    <th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
    <% if User.current.allowed_to?(:view_time_entries, @project) %>
    <th class="spent-time"><%=l(:label_spent_time)%>:</th>
    <td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %></td>
    <% end %>
    <% if @issue.estimated_hours %>
    <th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
    <% end %>
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>

<div style="clear: left;"><!-- --></div>

<hr />

<div class="contextual">
<%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>

<div class="wiki">
<%= textilizable @issue, :description, :attachments => @issue.attachments %>

<%= link_to_attachments @issue %>

<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>

<% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
<hr />
<div id="relations">
<%= render :partial => 'relations' %>
<% end %>

<% if User.current.allowed_to?(:add_issue_watchers, @project) ||
        (@issue.watchers.any? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
<hr />
<div id="watchers">
<%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
<% end %>


<% if @changesets.any? %>
<div id="issue-changesets">
<%= render :partial => 'changesets', :locals => { :changesets => @changesets} %>
<% end %>

<% if @journals.any? %>
<div id="history">
<%= render :partial => 'history', :locals => { :journals => @journals } %>
<% end %>

<%= render :partial => 'action_menu', :locals => {:replace_watcher => 'watcher2' } %>

<div style="clear: both;"></div>

<% if authorize_for('issues', 'edit') %>
  <div id="update" style="display:none;">
  <h3><%= l(:button_update) %></h3>
  <%= render :partial => 'edit' %>
<% end %>

<% other_formats_links do |f| %>
    <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
    <%= f.link_to 'PDF' %>
<% end %>

<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>

<% content_for :sidebar do %>
    <%= render :partial => 'issues/sidebar' %>
<% end %>

<% content_for :header_tags do %>
    <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
    <%= stylesheet_link_tag 'scm' %>
<% end %>

#31 Updated by Semyon Vyskubov about 7 years ago

PS: mobile.css is not completed. I've only tested it for basic pages like "My Page" and issues details.

#32 Updated by Semyon Vyskubov about 7 years ago

PSS: We're working with Redmine 1.0.0

#33 Updated by Semyon Vyskubov about 7 years ago

Oh... Sorry for lot of messages.
Just clarified version in /admin/info/ and here is a Redmine 0.9.4.stable.3733 (SQLite).
1.0.0 i've took from CHANGELOG file, and guess it's not a propper enough.
Thanks all!

#34 Updated by Ian Epperson about 7 years ago

I'm not sure the best approach is to use an app. An app wont pick up plugins easily nor grab any local changes. An app is good for allowing to add issues while offline, but challenging to update existing issues. Also an app is more challenging for open source development - it really needs to be owned by a single individual who is active in development, it doesn't work so well to pass it from developer to developer.

Anyway, this would be really cool to see happen. At some point, I could probably help hack on it a bit too.

#35 Updated by Daniel Felix over 4 years ago

  • Assignee deleted (Jim Mulholland)

A newer approach to solve this, would be the usage of media queries.
With this technology, there's a good way to customize the display of Redmine depending on the window width.

Further, I want to clarify, that there should be a MOBILE theme not just an iPhone specific theme.

This implementation won't be easy, as there are many rules which needs to be tweaked.

#36 Updated by Daniel Felix over 4 years ago

  • Status changed from New to Closed
  • Resolution set to Duplicate

Well, I rechecked #883.

I will close this issue, in favour of #883. As a mobile theme would be much better as an implementation for every mobile OS.
All iPhone user can use one of the good Apps or can use the normal mobile theme, which is described in #883.

#37 Updated by Jan from Planio www.plan.io over 2 years ago

  • Related to Feature #19097: Responsive layout for mobile devices added

#38 Updated by Toshi MARUYAMA almost 2 years ago

  • Related to deleted (Feature #19097: Responsive layout for mobile devices)

Also available in: Atom PDF