Browse Source

implement chrome custom tabs-based quick preview, minor drawer update

Andrew Dolgov 1 year ago
parent
commit
e1767e01c5

+ 1 - 1
build.gradle

@@ -4,7 +4,7 @@ buildscript {
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.0.0'
+        classpath 'com.android.tools.build:gradle:1.5.0'
     }
 }
 

+ 11 - 7
org.fox.ttirc/build.gradle

@@ -1,17 +1,19 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "20.0.0"
+    compileSdkVersion 23
+    buildToolsVersion "23"
 
     defaultConfig {
         applicationId "org.fox.ttirc"
         minSdkVersion 16
-        targetSdkVersion 21
+        targetSdkVersion 23
     }
 
     lintOptions {
-         abortOnError false
+        abortOnError false
+        checkReleaseBuilds false
+        disable 'MissingTranslation'
     }
 
     buildTypes {
@@ -20,13 +22,15 @@ android {
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
         }
     }
+
+    useLibrary 'org.apache.http.legacy'
 }
 
 dependencies {
     compile 'com.viewpagerindicator:library:2.4.1'
-    compile 'com.android.support:support-v4:21.0.3'
+    compile 'com.android.support:support-v4:23.1.1'
     compile 'com.google.code.gson:gson:2.3'
-    compile 'com.android.support:appcompat-v7:21.0.3'
+    compile 'com.android.support:appcompat-v7:23.1.1'
     compile 'ch.acra:acra:4.5.0'
-
+    compile 'com.android.support:customtabs:23.0.0'
 }

+ 28 - 27
org.fox.ttirc/org.fox.ttirc.iml

@@ -12,10 +12,12 @@
         <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
         <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
         <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
-        <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
-        <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
-        <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugTestSources" />
-        <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugTestSources" />
+        <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
+        <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
+        <afterSyncTasks>
+          <task>generateDebugAndroidTestSources</task>
+          <task>generateDebugSources</task>
+        </afterSyncTasks>
         <option name="ALLOW_USER_CONFIGURATION" value="false" />
         <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
         <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
@@ -24,9 +26,9 @@
       </configuration>
     </facet>
   </component>
-  <component name="NewModuleRootManager" inherit-compiler-output="false">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
     <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
-    <output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
+    <output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
     <exclude-output />
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
@@ -34,13 +36,13 @@
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
       <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/test/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/test/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/test/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/test/debug" isTestSource="true" generated="true" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/test/debug" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/test/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
@@ -63,34 +65,33 @@
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.1.1/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/customtabs/23.0.0/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.1.1/jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.viewpagerindicator/library/2.4.1/jars" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
       <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
       <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
     </content>
-    <orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
+    <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" exported="" name="appcompat-v7-21.0.3" level="project" />
     <orderEntry type="library" exported="" name="library-2.4.1" level="project" />
+    <orderEntry type="library" exported="" name="support-v4-23.1.1" level="project" />
     <orderEntry type="library" exported="" name="gson-2.3" level="project" />
-    <orderEntry type="library" exported="" name="support-v4-21.0.3" level="project" />
-    <orderEntry type="library" exported="" name="support-annotations-21.0.3" level="project" />
     <orderEntry type="library" exported="" name="acra-4.5.0" level="project" />
+    <orderEntry type="library" exported="" name="support-annotations-23.1.1" level="project" />
+    <orderEntry type="library" exported="" name="appcompat-v7-23.1.1" level="project" />
+    <orderEntry type="library" exported="" name="customtabs-23.0.0" level="project" />
+    <orderEntry type="library" exported="" name="org.apache.http.legacy-android-23" level="project" />
   </component>
 </module>

+ 2 - 13
org.fox.ttirc/src/main/AndroidManifest.xml

@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.fox.ttirc"
-    android:versionCode="77"
-    android:versionName="1.28" >
+    android:versionCode="78"
+    android:versionName="1.29" >
 
     <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
 
@@ -36,17 +36,6 @@
             android:label="@string/app_name"
             android:name=".CommonActivity" />
         <activity
-            android:label="@string/app_name"
-            android:theme="@style/QuickViewTheme"
-            android:configChanges="keyboardHidden|orientation|screenSize"
-            android:name=".QuickViewActivity">
-    		<intent-filter>
-    			<category android:name="android.intent.category.DEFAULT" />
-    			<action android:name="android.intent.action.VIEW" />
-    			<data android:scheme="org.fox.ttirc.quickview" />  
-			</intent-filter>    
-        </activity>
-        <activity
             android:label="@string/preferences"
             android:name=".PreferencesActivity" />
         <service

+ 22 - 3
org.fox.ttirc/src/main/java/org/fox/ttirc/ChannelFragment.java

@@ -8,6 +8,7 @@ import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -47,6 +48,7 @@ import org.fox.ttirc.backend.UpdateServiceApi;
 import org.fox.ttirc.backend.UpdateServiceListener;
 import org.fox.ttirc.types.Constants;
 import org.fox.ttirc.types.Message;
+import org.fox.ttirc.utils.CustomLinkify;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -697,16 +699,33 @@ public class ChannelFragment extends Fragment implements OnEditorActionListener,
 					break;		
 				}
 
-				if (m_prefs.getBoolean("quick_image_preview", true)) {
-					Pattern imgMatcher = Pattern.compile("(ftp|https?):\\/\\/[^ ]+\\.(jpe?g|png|gifv?|webm)", Pattern.CASE_INSENSITIVE);
+				if (m_prefs.getBoolean("enable_custom_tabs", true)) {
+					/*Pattern imgMatcher = Pattern.compile("(ftp|https?):\\/\\/[^ ]+\\.(jpe?g|png|gifv?|webm)", Pattern.CASE_INSENSITIVE);
 					String imgURL =    "org.fox.ttirc.quickview://view/";
 					Linkify.addLinks(holder.message, imgMatcher, imgURL);
 					
 					Pattern elseMatcher = Pattern.compile("(ftp|https?):\\/\\/[^ ]+(?!\\.(jpe?g|png|gifv?|webm))", Pattern.CASE_INSENSITIVE);
-					Linkify.addLinks(holder.message, elseMatcher, null);
+					Linkify.addLinks(holder.message, elseMatcher, null);*/
+
+					CustomLinkify.onClickListener = new CustomLinkify.OnClickListener() {
+						@Override
+						public void onClick(String url) {
+							if (m_activity != null) {
+								try {
+									m_activity.openUri(Uri.parse(url));
+								} catch (Exception e) {
+									e.printStackTrace();
+								}
+							}
+						}
+					};
+
+					CustomLinkify.addLinks(holder.message, Linkify.ALL);
+
 				} else {
 					Linkify.addLinks(holder.message, Linkify.ALL);
 				}
+
 			}
 		
 			return v;

+ 155 - 1
org.fox.ttirc/src/main/java/org/fox/ttirc/CommonActivity.java

@@ -1,11 +1,27 @@
 package org.fox.ttirc;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.DialogInterface;
+import android.content.Intent;
 import android.content.SharedPreferences;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
+import android.support.customtabs.CustomTabsCallback;
+import android.support.customtabs.CustomTabsClient;
+import android.support.customtabs.CustomTabsIntent;
+import android.support.customtabs.CustomTabsServiceConnection;
+import android.support.customtabs.CustomTabsSession;
 import android.support.v7.app.ActionBarActivity;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.Display;
+import android.view.View;
+import android.widget.CheckBox;
 import android.widget.Toast;
 
 import java.util.Arrays;
@@ -22,6 +38,21 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
 	protected SharedPreferences m_prefs;
 	private boolean m_needRestart;
 
+	protected CustomTabsClient m_customTabClient;
+	protected CustomTabsServiceConnection m_customTabServiceConnection = new CustomTabsServiceConnection() {
+		@Override
+		public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient customTabsClient) {
+			m_customTabClient = customTabsClient;
+
+			m_customTabClient.warmup(0);
+		}
+
+		@Override
+		public void onServiceDisconnected(ComponentName componentName) {
+			m_customTabClient = null;
+		}
+	};
+
 	protected void setSmallScreen(boolean smallScreen) {
 		Log.d(TAG, "m_smallScreenMode=" + smallScreen);
 		m_smallScreenMode = smallScreen;
@@ -39,6 +70,11 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
 
 	@Override
 	public void onDestroy() {
+
+		if (m_customTabServiceConnection != null) {
+			unbindService(m_customTabServiceConnection);
+		}
+
 		super.onDestroy();
 	}
 
@@ -54,6 +90,8 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
 			m_themeName = m_prefs.getString("theme", THEME_DEFAULT);
 		}
 
+		CustomTabsClient.bindCustomTabsService(this, "com.android.chrome", m_customTabServiceConnection);
+
 		super.onCreate(savedInstanceState);
 	}
 	
@@ -98,7 +136,123 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
 		
 		out.putString("theme", m_themeName);
 	}
-	
+
+	private CustomTabsSession getCustomTabSession() {
+		return m_customTabClient.newSession(new CustomTabsCallback() {
+			@Override
+			public void onNavigationEvent(int navigationEvent, Bundle extras) {
+				super.onNavigationEvent(navigationEvent, extras);
+			}
+		});
+	}
+
+	private void openUriWithCustomTab(Uri uri) {
+		if (m_customTabClient != null) {
+			TypedValue tvBackground = new TypedValue();
+			getTheme().resolveAttribute(R.attr.colorPrimary, tvBackground, true);
+
+			CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getCustomTabSession());
+
+			builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left);
+			builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right);
+
+			builder.setToolbarColor(tvBackground.data);
+
+			Intent shareIntent = new Intent(Intent.ACTION_SEND);
+			shareIntent.setType("text/plain");
+			shareIntent.putExtra(Intent.EXTRA_SUBJECT, uri.toString());
+			shareIntent.putExtra(Intent.EXTRA_TEXT, uri.toString());
+
+			PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, shareIntent, 0);
+
+			builder.setActionButton(BitmapFactory.decodeResource(getResources(), R.drawable.ic_share),
+					getString(R.string.share_url), pendingIntent);
+
+			CustomTabsIntent intent = builder.build();
+
+			intent.launchUrl(this, uri);
+		}
+	}
+
+	// uses chrome custom tabs when available
+	public void openUri(final Uri uri) {
+		boolean enableCustomTabs = m_prefs.getBoolean("enable_custom_tabs", true);
+		final boolean askEveryTime = m_prefs.getBoolean("custom_tabs_ask_always", true);
+
+		if (enableCustomTabs && m_customTabClient != null) {
+
+			if (askEveryTime) {
+
+				View dialogView = View.inflate(this, R.layout.dialog_open_link_askcb, null);
+				final CheckBox askEveryTimeCB = (CheckBox) dialogView.findViewById(R.id.open_link_ask_checkbox);
+
+				AlertDialog.Builder builder = new AlertDialog.Builder(
+						CommonActivity.this)
+						.setTitle(R.string.open_link)
+						.setView(dialogView)
+						.setMessage(uri.toString())
+						.setPositiveButton(R.string.quick_preview,
+								new Dialog.OnClickListener() {
+									public void onClick(DialogInterface dialog,
+														int which) {
+
+										if (!askEveryTimeCB.isChecked()) {
+											SharedPreferences.Editor editor = m_prefs.edit();
+											editor.putBoolean("custom_tabs_ask_always", false);
+											editor.apply();
+										}
+
+										openUriWithCustomTab(uri);
+
+									}
+								})
+						.setNegativeButton(R.string.open_with_app,
+								new Dialog.OnClickListener() {
+									public void onClick(DialogInterface dialog,
+														int which) {
+
+										if (!askEveryTimeCB.isChecked()) {
+											SharedPreferences.Editor editor = m_prefs.edit();
+											editor.putBoolean("custom_tabs_ask_always", false);
+											editor.putBoolean("enable_custom_tabs", false);
+											editor.apply();
+										}
+
+										Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+
+										startActivity(intent);
+
+									}
+								});
+						/*.setNegativeButton(R.string.cancel,
+							new Dialog.OnClickListener() {
+								public void onClick(DialogInterface dialog,
+													int which) {
+
+									if (!askEveryTimeCB.isChecked()) {
+										SharedPreferences.Editor editor = m_prefs.edit();
+										editor.putBoolean("custom_tabs_ask_always", false);
+										editor.apply();
+									}
+
+								}
+							});*/
+
+				AlertDialog dlg = builder.create();
+				dlg.show();
+
+			} else {
+				openUriWithCustomTab(uri);
+			}
+
+		} else {
+			Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+
+			startActivity(intent);
+		}
+	}
+
+
 	/* @SuppressLint("NewApi")
 	@SuppressWarnings("deprecation")
 	public void copyToClipboard(String str) {

+ 15 - 0
org.fox.ttirc/src/main/java/org/fox/ttirc/ConnectionsFragment.java

@@ -136,6 +136,21 @@ public class ConnectionsFragment extends Fragment implements
             server.setText("");
         }
 
+		View settings = view.findViewById(R.id.drawer_settings_btn);
+
+		settings.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				try {
+					Intent intent = new Intent(getActivity(),
+							PreferencesActivity.class);
+					startActivityForResult(intent, 0);
+				} catch (Exception e) {
+
+				}
+			}
+		});
+
 		m_list.setOnItemClickListener(this);
 
 		m_adapter = new ConnectionListAdapter(m_activity,

+ 0 - 121
org.fox.ttirc/src/main/java/org/fox/ttirc/QuickViewActivity.java

@@ -1,121 +0,0 @@
-package org.fox.ttirc;
-
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v7.widget.Toolbar;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Button;
-import android.widget.ProgressBar;
-
-
-public class QuickViewActivity extends CommonActivity {
-    private final String TAG = this.getClass().getSimpleName();
-
-    private SharedPreferences m_prefs;
-
-    public void onCreate(Bundle savedInstanceState) {
-        Log.d(TAG, "onCreate");
-
-        m_prefs = PreferenceManager
-                .getDefaultSharedPreferences(getApplicationContext());
-
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.activity_quickview);
-
-        //Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
-        //setSupportActionBar(toolbar);
-
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
-        final String url = getIntent().getData().getPath().substring(1);
-
-        if (url == null) {
-            finish();
-            return;
-        }
-
-        setTitle(url);
-
-        Button open_url = (Button) findViewById(R.id.quickview_open_url);
-
-        open_url.setOnClickListener(new View.OnClickListener() {
-
-            @Override
-            public void onClick(View v) {
-                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-                startActivity(intent);
-                finish();
-            }
-        });
-
-        Button close = (Button) findViewById(R.id.quickview_close);
-
-        final ProgressBar progressBar = (ProgressBar) findViewById(R.id.quickview_progress);
-
-        if (open_url != null) {
-            close.setOnClickListener(new View.OnClickListener() {
-
-                @Override
-                public void onClick(View v) {
-                    finish();
-                }
-            });
-
-            WebView web = (WebView) findViewById(R.id.quickview_content);
-
-            if (web != null) {
-                WebSettings ws = web.getSettings();
-                ws.setSupportZoom(true);
-                ws.setJavaScriptEnabled(true);
-                ws.setLoadWithOverviewMode(true);
-                ws.setUseWideViewPort(true);
-                ws.setJavaScriptCanOpenWindowsAutomatically(false);
-                ws.setBuiltInZoomControls(false);
-
-                web.setWebChromeClient(new WebChromeClient() {
-                    @Override
-                    public void onProgressChanged(WebView view, int progress) {
-                        if (progressBar != null) {
-                            progressBar.setProgress(progress);
-                            progressBar.setVisibility(progress < 100 ? View.VISIBLE : View.INVISIBLE);
-                        }
-                    }
-                });
-                web.setBackgroundColor(getResources().getColor(android.R.color.black));
-                web.setWebViewClient(new WebViewClient() {
-                    @Override
-                    public boolean shouldOverrideUrlLoading(WebView view, String url) {
-                        view.loadUrl(url);
-                        return true;
-                    }
-                });
-
-                web.loadUrl(url);
-            }
-
-        }
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-
-        switch (item.getItemId()) {
-            case android.R.id.home:
-                finish();
-                return true;
-            default:
-                return super.onOptionsItemSelected(item);
-        }
-    }
-
-}

+ 557 - 0
org.fox.ttirc/src/main/java/org/fox/ttirc/utils/CustomLinkify.java

@@ -0,0 +1,557 @@
+package org.fox.ttirc.utils;
+
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+        import android.telephony.PhoneNumberUtils;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.method.MovementMethod;
+import android.text.style.URLSpan;
+import android.util.Patterns;
+        import android.view.View;
+        import android.webkit.WebView;
+import android.widget.TextView;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *  Linkify take a piece of text and a regular expression and turns all of the
+ *  regex matches in the text into clickable links.  This is particularly
+ *  useful for matching things like email addresses, web urls, etc. and making
+ *  them actionable.
+ *
+ *  Alone with the pattern that is to be matched, a url scheme prefix is also
+ *  required.  Any pattern match that does not begin with the supplied scheme
+ *  will have the scheme prepended to the matched text when the clickable url
+ *  is created.  For instance, if you are matching web urls you would supply
+ *  the scheme <code>http://</code>.  If the pattern matches example.com, which
+ *  does not have a url scheme prefix, the supplied scheme will be prepended to
+ *  create <code>http://example.com</code> when the clickable url link is
+ *  created.
+ */
+
+public class CustomLinkify {
+    public static CustomLinkify.OnClickListener onClickListener;
+
+    /**
+     *  Bit field indicating that web URLs should be matched in methods that
+     *  take an options mask
+     */
+    public static final int WEB_URLS = 0x01;
+
+    /**
+     *  Bit field indicating that email addresses should be matched in methods
+     *  that take an options mask
+     */
+    public static final int EMAIL_ADDRESSES = 0x02;
+
+    /**
+     *  Bit field indicating that phone numbers should be matched in methods that
+     *  take an options mask
+     */
+    public static final int PHONE_NUMBERS = 0x04;
+
+    /**
+     *  Bit field indicating that street addresses should be matched in methods that
+     *  take an options mask. Note that this uses the
+     *  {@link android.webkit.WebView#findAddress(String) findAddress()} method in
+     *  {@link android.webkit.WebView} for finding addresses, which has various
+     *  limitations.
+     */
+    public static final int MAP_ADDRESSES = 0x08;
+
+    /**
+     *  Bit mask indicating that all available patterns should be matched in
+     *  methods that take an options mask
+     */
+    public static final int ALL = WEB_URLS | EMAIL_ADDRESSES | PHONE_NUMBERS | MAP_ADDRESSES;
+
+    /**
+     * Don't treat anything with fewer than this many digits as a
+     * phone number.
+     */
+    private static final int PHONE_NUMBER_MINIMUM_DIGITS = 5;
+
+    /**
+     *  Filters out web URL matches that occur after an at-sign (@).  This is
+     *  to prevent turning the domain name in an email address into a web link.
+     */
+    public static final MatchFilter sUrlMatchFilter = new MatchFilter() {
+        public final boolean acceptMatch(CharSequence s, int start, int end) {
+            if (start == 0) {
+                return true;
+            }
+
+            if (s.charAt(start - 1) == '@') {
+                return false;
+            }
+
+            return true;
+        }
+    };
+
+    /**
+     *  Filters out URL matches that don't have enough digits to be a
+     *  phone number.
+     */
+    public static final MatchFilter sPhoneNumberMatchFilter = new MatchFilter() {
+        public final boolean acceptMatch(CharSequence s, int start, int end) {
+            int digitCount = 0;
+
+            for (int i = start; i < end; i++) {
+                if (Character.isDigit(s.charAt(i))) {
+                    digitCount++;
+                    if (digitCount >= PHONE_NUMBER_MINIMUM_DIGITS) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    };
+
+    /**
+     *  Transforms matched phone number text into something suitable
+     *  to be used in a tel: URL.  It does this by removing everything
+     *  but the digits and plus signs.  For instance:
+     *  &apos;+1 (919) 555-1212&apos;
+     *  becomes &apos;+19195551212&apos;
+     */
+    public static final TransformFilter sPhoneNumberTransformFilter = new TransformFilter() {
+        public final String transformUrl(final Matcher match, String url) {
+            return Patterns.digitsAndPlusOnly(match);
+        }
+    };
+
+    /**
+     *  MatchFilter enables client code to have more control over
+     *  what is allowed to match and become a link, and what is not.
+     *
+     *  For example:  when matching web urls you would like things like
+     *  http://www.example.com to match, as well as just example.com itelf.
+     *  However, you would not want to match against the domain in
+     *  support@example.com.  So, when matching against a web url pattern you
+     *  might also include a MatchFilter that disallows the match if it is
+     *  immediately preceded by an at-sign (@).
+     */
+    public interface MatchFilter {
+        /**
+         *  Examines the character span matched by the pattern and determines
+         *  if the match should be turned into an actionable link.
+         *
+         *  @param s        The body of text against which the pattern
+         *                  was matched
+         *  @param start    The index of the first character in s that was
+         *                  matched by the pattern - inclusive
+         *  @param end      The index of the last character in s that was
+         *                  matched - exclusive
+         *
+         *  @return         Whether this match should be turned into a link
+         */
+        boolean acceptMatch(CharSequence s, int start, int end);
+    }
+
+    /**
+     *  TransformFilter enables client code to have more control over
+     *  how matched patterns are represented as URLs.
+     *
+     *  For example:  when converting a phone number such as (919)  555-1212
+     *  into a tel: URL the parentheses, white space, and hyphen need to be
+     *  removed to produce tel:9195551212.
+     */
+    public interface TransformFilter {
+        /**
+         *  Examines the matched text and either passes it through or uses the
+         *  data in the Matcher state to produce a replacement.
+         *
+         *  @param match    The regex matcher state that found this URL text
+         *  @param url      The text that was matched
+         *
+         *  @return         The transformed form of the URL
+         */
+        String transformUrl(final Matcher match, String url);
+    }
+
+    /**
+     *  Scans the text of the provided Spannable and turns all occurrences
+     *  of the link types indicated in the mask into clickable links.
+     *  If the mask is nonzero, it also removes any existing URLSpans
+     *  attached to the Spannable, to avoid problems if you call it
+     *  repeatedly on the same text.
+     */
+    public static final boolean addLinks(Spannable text, int mask) {
+        if (mask == 0) {
+            return false;
+        }
+
+        URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class);
+
+        for (int i = old.length - 1; i >= 0; i--) {
+            text.removeSpan(old[i]);
+        }
+
+        ArrayList<LinkSpec> links = new ArrayList<LinkSpec>();
+
+        if ((mask & WEB_URLS) != 0) {
+            gatherLinks(links, text, Patterns.WEB_URL,
+                    new String[] { "http://", "https://", "rtsp://" },
+                    sUrlMatchFilter, null);
+        }
+
+        if ((mask & EMAIL_ADDRESSES) != 0) {
+            gatherLinks(links, text, Patterns.EMAIL_ADDRESS,
+                    new String[] { "mailto:" },
+                    null, null);
+        }
+
+        if ((mask & MAP_ADDRESSES) != 0) {
+            gatherMapLinks(links, text);
+        }
+
+        pruneOverlaps(links);
+
+        if (links.size() == 0) {
+            return false;
+        }
+
+        for (LinkSpec link: links) {
+            applyLink(link.url, link.start, link.end, text);
+        }
+
+        return true;
+    }
+
+    /**
+     *  Scans the text of the provided TextView and turns all occurrences of
+     *  the link types indicated in the mask into clickable links.  If matches
+     *  are found the movement method for the TextView is set to
+     *  LinkMovementMethod.
+     */
+    public static final boolean addLinks(TextView text, int mask) {
+        if (mask == 0) {
+            return false;
+        }
+
+        CharSequence t = text.getText();
+
+        if (t instanceof Spannable) {
+            if (addLinks((Spannable) t, mask)) {
+                addLinkMovementMethod(text);
+                return true;
+            }
+
+            return false;
+        } else {
+            SpannableString s = SpannableString.valueOf(t);
+
+            if (addLinks(s, mask)) {
+                addLinkMovementMethod(text);
+                text.setText(s);
+
+                return true;
+            }
+
+            return false;
+        }
+    }
+
+    private static final void addLinkMovementMethod(TextView t) {
+        MovementMethod m = t.getMovementMethod();
+
+        if ((m == null) || !(m instanceof LinkMovementMethod)) {
+            if (t.getLinksClickable()) {
+                t.setMovementMethod(LinkMovementMethod.getInstance());
+            }
+        }
+    }
+
+    /**
+     *  Applies a regex to the text of a TextView turning the matches into
+     *  links.  If links are found then UrlSpans are applied to the link
+     *  text match areas, and the movement method for the text is changed
+     *  to LinkMovementMethod.
+     *
+     *  @param text         TextView whose text is to be marked-up with links
+     *  @param pattern      Regex pattern to be used for finding links
+     *  @param scheme       Url scheme string (eg <code>http://</code> to be
+     *                      prepended to the url of links that do not have
+     *                      a scheme specified in the link text
+     */
+    public static final void addLinks(TextView text, Pattern pattern, String scheme) {
+        addLinks(text, pattern, scheme, null, null);
+    }
+
+    /**
+     *  Applies a regex to the text of a TextView turning the matches into
+     *  links.  If links are found then UrlSpans are applied to the link
+     *  text match areas, and the movement method for the text is changed
+     *  to LinkMovementMethod.
+     *
+     *  @param text         TextView whose text is to be marked-up with links
+     *  @param p            Regex pattern to be used for finding links
+     *  @param scheme       Url scheme string (eg <code>http://</code> to be
+     *                      prepended to the url of links that do not have
+     *                      a scheme specified in the link text
+     *  @param matchFilter  The filter that is used to allow the client code
+     *                      additional control over which pattern matches are
+     *                      to be converted into links.
+     */
+    public static final void addLinks(TextView text, Pattern p, String scheme,
+                                      MatchFilter matchFilter, TransformFilter transformFilter) {
+        SpannableString s = SpannableString.valueOf(text.getText());
+
+        if (addLinks(s, p, scheme, matchFilter, transformFilter)) {
+            text.setText(s);
+            addLinkMovementMethod(text);
+        }
+    }
+
+    /**
+     *  Applies a regex to a Spannable turning the matches into
+     *  links.
+     *
+     *  @param text         Spannable whose text is to be marked-up with
+     *                      links
+     *  @param pattern      Regex pattern to be used for finding links
+     *  @param scheme       Url scheme string (eg <code>http://</code> to be
+     *                      prepended to the url of links that do not have
+     *                      a scheme specified in the link text
+     */
+    public static final boolean addLinks(Spannable text, Pattern pattern, String scheme) {
+        return addLinks(text, pattern, scheme, null, null);
+    }
+
+    /**
+     *  Applies a regex to a Spannable turning the matches into
+     *  links.
+     *
+     *  @param s            Spannable whose text is to be marked-up with
+     *                      links
+     *  @param p            Regex pattern to be used for finding links
+     *  @param scheme       Url scheme string (eg <code>http://</code> to be
+     *                      prepended to the url of links that do not have
+     *                      a scheme specified in the link text
+     *  @param matchFilter  The filter that is used to allow the client code
+     *                      additional control over which pattern matches are
+     *                      to be converted into links.
+     */
+    public static final boolean addLinks(Spannable s, Pattern p,
+                                         String scheme, MatchFilter matchFilter,
+                                         TransformFilter transformFilter) {
+        boolean hasMatches = false;
+        String prefix = (scheme == null) ? "" : scheme.toLowerCase(Locale.ROOT);
+        Matcher m = p.matcher(s);
+
+        while (m.find()) {
+            int start = m.start();
+            int end = m.end();
+            boolean allowed = true;
+
+            if (matchFilter != null) {
+                allowed = matchFilter.acceptMatch(s, start, end);
+            }
+
+            if (allowed) {
+                String url = makeUrl(m.group(0), new String[] { prefix },
+                        m, transformFilter);
+
+                applyLink(url, start, end, s);
+                hasMatches = true;
+            }
+        }
+
+        return hasMatches;
+    }
+
+    private static final void applyLink(final String url, int start, int end, Spannable text) {
+        URLSpan span = new URLSpan(url) {
+            @Override
+            public void onClick(View widget)
+            {
+                CustomLinkify.onClickListener.onClick(url);
+            }
+        };
+
+        text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+
+    private static final String makeUrl(String url, String[] prefixes,
+                                        Matcher m, TransformFilter filter) {
+        if (filter != null) {
+            url = filter.transformUrl(m, url);
+        }
+
+        boolean hasPrefix = false;
+
+        for (int i = 0; i < prefixes.length; i++) {
+            if (url.regionMatches(true, 0, prefixes[i], 0,
+                    prefixes[i].length())) {
+                hasPrefix = true;
+
+                // Fix capitalization if necessary
+                if (!url.regionMatches(false, 0, prefixes[i], 0,
+                        prefixes[i].length())) {
+                    url = prefixes[i] + url.substring(prefixes[i].length());
+                }
+
+                break;
+            }
+        }
+
+        if (!hasPrefix) {
+            url = prefixes[0] + url;
+        }
+
+        return url;
+    }
+
+    private static final void gatherLinks(ArrayList<LinkSpec> links,
+                                          Spannable s, Pattern pattern, String[] schemes,
+                                          MatchFilter matchFilter, TransformFilter transformFilter) {
+        Matcher m = pattern.matcher(s);
+
+        while (m.find()) {
+            int start = m.start();
+            int end = m.end();
+
+            if (matchFilter == null || matchFilter.acceptMatch(s, start, end)) {
+                LinkSpec spec = new LinkSpec();
+                String url = makeUrl(m.group(0), schemes, m, transformFilter);
+
+                spec.url = url;
+                spec.start = start;
+                spec.end = end;
+
+                links.add(spec);
+            }
+        }
+    }
+
+    private static final void gatherMapLinks(ArrayList<LinkSpec> links, Spannable s) {
+        String string = s.toString();
+        String address;
+        int base = 0;
+
+        try {
+            while ((address = WebView.findAddress(string)) != null) {
+                int start = string.indexOf(address);
+
+                if (start < 0) {
+                    break;
+                }
+
+                LinkSpec spec = new LinkSpec();
+                int length = address.length();
+                int end = start + length;
+
+                spec.start = base + start;
+                spec.end = base + end;
+                string = string.substring(end);
+                base += end;
+
+                String encodedAddress = null;
+
+                try {
+                    encodedAddress = URLEncoder.encode(address,"UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    continue;
+                }
+
+                spec.url = "geo:0,0?q=" + encodedAddress;
+                links.add(spec);
+            }
+        } catch (UnsupportedOperationException e) {
+            // findAddress may fail with an unsupported exception on platforms without a WebView.
+            // In this case, we will not append anything to the links variable: it would have died
+            // in WebView.findAddress.
+            return;
+        }
+    }
+
+    private static final void pruneOverlaps(ArrayList<LinkSpec> links) {
+        Comparator<LinkSpec>  c = new Comparator<LinkSpec>() {
+            public final int compare(LinkSpec a, LinkSpec b) {
+                if (a.start < b.start) {
+                    return -1;
+                }
+
+                if (a.start > b.start) {
+                    return 1;
+                }
+
+                if (a.end < b.end) {
+                    return 1;
+                }
+
+                if (a.end > b.end) {
+                    return -1;
+                }
+
+                return 0;
+            }
+        };
+
+        Collections.sort(links, c);
+
+        int len = links.size();
+        int i = 0;
+
+        while (i < len - 1) {
+            LinkSpec a = links.get(i);
+            LinkSpec b = links.get(i + 1);
+            int remove = -1;
+
+            if ((a.start <= b.start) && (a.end > b.start)) {
+                if (b.end <= a.end) {
+                    remove = i + 1;
+                } else if ((a.end - a.start) > (b.end - b.start)) {
+                    remove = i + 1;
+                } else if ((a.end - a.start) < (b.end - b.start)) {
+                    remove = i;
+                }
+
+                if (remove != -1) {
+                    links.remove(remove);
+                    len--;
+                    continue;
+                }
+
+            }
+
+            i++;
+        }
+    }
+
+    public interface OnClickListener {
+        public void onClick(String url);
+    }
+}
+
+class LinkSpec {
+    String url;
+    int start;
+    int end;
+}

+ 0 - 56
org.fox.ttirc/src/main/res/layout/activity_quickview.xml

@@ -1,56 +0,0 @@
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="fill_parent"
-        android:animateLayoutChanges="true"
-        android:layout_height="fill_parent" >
-
-        <WebView
-            android:background="?android:colorBackground"
-            android:id="@+id/quickview_content"
-            android:adjustViewBounds="true"
-            android:layout_gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_below="@+id/toolbar"
-            android:layout_above="@+id/quickview_buttons" />
-
-        <!-- <include layout="@layout/toolbar" android:id="@+id/toolbar" /> -->
-
-        <ProgressBar
-            style="?android:attr/progressBarStyleHorizontal"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/quickview_progress"
-            android:layout_below="@+id/toolbar"
-            android:layout_alignParentLeft="true"
-            android:layout_alignParentStart="true"
-            android:layout_alignParentRight="true"
-            android:layout_alignParentEnd="true"
-            android:max="100"
-            android:progress="0" />
-
-        <LinearLayout
-            android:layout_alignParentBottom="true"
-            style="?android:attr/buttonBarStyle"
-            android:elevation="8dp"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:id="@+id/quickview_buttons">
-
-            <Button
-                android:id="@+id/quickview_close"
-                style="?android:attr/buttonBarButtonStyle"
-                android:layout_weight="1"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:text="@string/close" />
-
-            <Button
-                android:id="@+id/quickview_open_url"
-                style="?android:attr/buttonBarButtonStyle"
-                android:layout_width="fill_parent"
-                android:layout_weight="1"
-                android:layout_height="wrap_content"
-                android:text="@string/open_url" />
-        </LinearLayout>
-
-    </RelativeLayout>

+ 14 - 0
org.fox.ttirc/src/main/res/layout/dialog_open_link_askcb.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:layout_height="match_parent">
+
+    <CheckBox
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/ask_me_every_time"
+        android:checked="true"
+        android:id="@+id/open_link_ask_checkbox" />
+</FrameLayout>

+ 50 - 53
org.fox.ttirc/src/main/res/layout/drawer_header.xml

@@ -1,75 +1,71 @@
 <?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="120dp"
     android:orientation="vertical"
     android:weightSum="1"
     android:clickable="false">
 
-
     <ImageView
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:id="@+id/imageView"
+        android:scaleType="fitXY"
         android:background="?colorPrimaryDark"
-        android:src="?drawer_header"
-        android:scaleType="fitStart" />
+        android:src="?drawer_header" />
 
     <FrameLayout
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:background="@drawable/circle_bg"
-        android:clickable="true"
-        android:layout_centerVertical="true"
-        android:layout_alignParentRight="true"
-        android:layout_alignParentEnd="true"
-        android:layout_marginRight="16dp"
-        android:elevation="8dp">
-
-        <ImageView
-            android:id="@+id/drawer_header_account"
-            android:background="@drawable/ripple"
-            android:layout_width="36dp"
-            android:layout_height="36dp"
-            android:tint="?colorAccent"
-            android:src="@drawable/ic_account"
-            android:layout_gravity="center" />
-    </FrameLayout>
-
-    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="56dp"
-        android:orientation="vertical"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentStart="true"
-        android:id="@+id/linearLayout">
+        android:background="@android:color/transparent"
+        android:layout_height="match_parent">
 
-        <TextView
-            android:id="@+id/drawer_header_login"
+        <ImageView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="16dp"
-            android:textColor="@android:color/primary_text_dark"
-            android:text="test"
-            android:textSize="14sp"
-            android:textStyle="bold"
+            android:src="@drawable/ic_settings"
+            android:id="@+id/drawer_settings_btn"
+            android:layout_gravity="bottom|right"
+            android:clickable="true"
+            android:layout_marginBottom="16dp"
+            android:layout_marginRight="12dp"
+            android:background="@drawable/ripple" />
 
-            />
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="56dp"
+            android:orientation="vertical"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
+            android:id="@+id/linearLayout"
+            android:layout_gravity="center_horizontal|bottom">
 
-        <TextView
-            android:id="@+id/drawer_header_server"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textColor="@android:color/primary_text_dark"
-            android:layout_marginLeft="16dp"
-            android:layout_marginTop="5dp"
-            android:text="example.org"
-            android:textSize="14sp"
-            android:textStyle="normal"
+            <TextView
+                android:id="@+id/drawer_header_login"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="16dp"
+                android:textColor="@android:color/primary_text_dark"
+                android:text="test"
+                android:textSize="14sp"
+                android:textStyle="bold"
+
+                />
 
-            />
-    </LinearLayout>
+            <TextView
+                android:id="@+id/drawer_header_server"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="@android:color/primary_text_dark"
+                android:layout_marginLeft="16dp"
+                android:layout_marginTop="5dp"
+                android:text="example.org"
+                android:textSize="14sp"
+                android:textStyle="normal"
+
+                />
+        </LinearLayout>
+    </FrameLayout>
 
     <ProgressBar
         style="?android:attr/progressBarStyleHorizontal"
@@ -79,5 +75,6 @@
         android:layout_height="wrap_content"
         android:id="@+id/loading_bar"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentBottom="true" />
-</RelativeLayout>
+        android:layout_alignParentBottom="true"
+        android:layout_gravity="bottom" />
+</FrameLayout>

+ 0 - 4
org.fox.ttirc/src/main/res/menu/activity_main.xml

@@ -44,10 +44,6 @@
     </group>
 
     <item
-        android:id="@+id/preferences"
-        android:icon="@drawable/ic_settings"
-        android:title="@string/preferences"/>
-    <item
         android:id="@+id/logout"
         android:icon="@drawable/ic_logout"
         ugh:showAsAction=""

+ 6 - 0
org.fox.ttirc/src/main/res/values/dimens.xml

@@ -0,0 +1,6 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="widget_margin">0dp</dimen> <!-- we're v14+ anyway -->
+</resources>

+ 8 - 0
org.fox.ttirc/src/main/res/values/strings.xml

@@ -112,4 +112,12 @@
     <string name="crash_dialog_text">Unfortunately, Tiny Tiny IRC has stopped. Submit crash report to tt-rss.org?</string>
     <string name="menu_channel_emoticons">Emoticons</string>
     <string name="close">Close</string>
+    <string name="share_url">Share URL</string>
+    <string name="open_link">Open link</string>
+    <string name="quick_preview">Quick preview</string>
+    <string name="open_with_app">Open with app</string>
+    <string name="prefs_custom_tabs_summary">Open external links with Chrome custom tabs (faster, used if available)</string>
+    <string name="prefs_use_custom_tabs">Use quick preview</string>
+    <string name="prefs_opening_links">Opening links</string>
+    <string name="ask_me_every_time">Ask me every time</string>
 </resources>

+ 14 - 2
org.fox.ttirc/src/main/res/xml/preferences.xml

@@ -69,10 +69,10 @@
             android:key="enable_emoticons"
             android:title="@string/pref_display_emoticons" />
         
-        <org.fox.ttirc.utils.LessBrokenSwitchPreference
+        <!-- <org.fox.ttirc.utils.LessBrokenSwitchPreference
             android:defaultValue="true"
             android:key="quick_image_preview"
-            android:title="@string/quick_image_preview" />
+            android:title="@string/quick_image_preview" /> -->
         
         <!--  <org.fox.ttirc.utils.LessBrokenSwitchPreference
             android:defaultValue="false"
@@ -107,6 +107,18 @@
         
     </PreferenceCategory>
 
+    <PreferenceCategory android:title="@string/prefs_opening_links" >
+        <org.fox.ttirc.utils.LessBrokenSwitchPreference
+            android:defaultValue="true"
+            android:key="enable_custom_tabs"
+            android:summary="@string/prefs_custom_tabs_summary"
+            android:title="@string/prefs_use_custom_tabs" />
+        <org.fox.ttrss.util.LessBrokenSwitchPreference
+            android:defaultValue="true"
+            android:key="custom_tabs_ask_always"
+            android:title="@string/ask_me_every_time" />
+    </PreferenceCategory>
+
     <PreferenceCategory android:title="@string/debugging" >
         <org.fox.ttirc.utils.LessBrokenSwitchPreference
             android:defaultValue="false"

+ 1 - 3
tt-irc-android.iml

@@ -8,9 +8,7 @@
       </configuration>
     </facet>
   </component>
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <output url="file://$MODULE_DIR$/build/classes/main" />
-    <output-test url="file://$MODULE_DIR$/build/classes/test" />
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
     <exclude-output />
     <content url="file://$MODULE_DIR$">
       <excludeFolder url="file://$MODULE_DIR$/.gradle" />