Skip to content
Snippets Groups Projects
Commit 83e60bf3 authored by Jawnnypoo's avatar Jawnnypoo
Browse files

Create some kind of widget

parent 4904864a
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 398 additions and 53 deletions
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.commit451.gitlab">
package="com.commit451.gitlab">
 
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
 
<application
android:name=".LabCoatApp"
Loading
Loading
@@ -15,48 +15,55 @@
android:label="@string/app_name"
android:theme="@style/AppTheme">
 
<meta-data
android:name="io.fabric.ApiKey"
android:value="${fabric_key}" />
<activity
android:name=".activity.LaunchActivity"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
 
<activity
android:name=".activity.ProjectsActivity"
android:theme="@style/Activity.Projects"
android:launchMode="singleTask"/>
android:launchMode="singleTask"
android:theme="@style/Activity.Projects" />
<activity
android:name=".activity.GroupsActivity"
android:theme="@style/Activity.Groups"
android:launchMode="singleTask"/>
android:launchMode="singleTask"
android:theme="@style/Activity.Groups" />
<activity
android:name=".activity.ActivityActivity"
android:theme="@style/Activity.Activity"
android:launchMode="singleTask"/>
<activity android:name=".activity.ProjectActivity"/>
<activity android:name=".activity.LoginActivity"/>
<activity android:name=".activity.FileActivity"/>
<activity android:name=".activity.IssueActivity"/>
<activity android:name=".activity.DiffActivity"/>
<activity android:name=".activity.AboutActivity"/>
<activity android:name=".activity.AddUserActivity"/>
<activity android:name=".activity.UserActivity"
android:theme="@style/Activity.User"/>
<activity android:name=".activity.SearchActivity"/>
<activity android:name=".activity.GroupActivity"
android:theme="@style/Activity.Group"/>
<activity android:name=".activity.MergeRequestActivity"/>
<activity android:name=".activity.AddIssueActivity"/>
<activity android:name=".activity.MilestoneActivity"/>
<activity android:name=".activity.AddMilestoneActivity"/>
<activity android:name=".activity.BuildActivity"/>
<activity android:name=".activity.LoadSomeInfoActivity"
android:theme="@style/Activity.Translucent"/>
<activity android:name=".activity.SettingsActivity"/>
android:launchMode="singleTask"
android:theme="@style/Activity.Activity" />
<activity android:name=".activity.ProjectActivity" />
<activity android:name=".activity.LoginActivity" />
<activity android:name=".activity.FileActivity" />
<activity android:name=".activity.IssueActivity" />
<activity android:name=".activity.DiffActivity" />
<activity android:name=".activity.AboutActivity" />
<activity android:name=".activity.AddUserActivity" />
<activity
android:name=".activity.UserActivity"
android:theme="@style/Activity.User" />
<activity android:name=".activity.SearchActivity" />
<activity
android:name=".activity.GroupActivity"
android:theme="@style/Activity.Group" />
<activity android:name=".activity.MergeRequestActivity" />
<activity android:name=".activity.AddIssueActivity" />
<activity android:name=".activity.MilestoneActivity" />
<activity android:name=".activity.AddMilestoneActivity" />
<activity android:name=".activity.BuildActivity" />
<activity
android:name=".activity.LoadSomeInfoActivity"
android:theme="@style/Activity.Translucent" />
<activity android:name=".activity.SettingsActivity" />
 
<activity
android:name=".activity.RoutingActivity"
Loading
Loading
@@ -65,19 +72,28 @@
android:theme="@android:style/Theme.NoDisplay">
<!-- Standard Url -->
<intent-filter android:label="@string/deeplink_text">
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.VIEW" />
 
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
 
<data
android:scheme="@string/deeplink_scheme"/>
<data android:scheme="@string/deeplink_scheme" />
</intent-filter>
</activity>
 
<meta-data
android:name="io.fabric.ApiKey"
android:value="${fabric_key}"/>
<receiver android:name=".widget.StackWidgetProvider"
android:label="GitLab Feed">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_feed" />
</receiver>
<service
android:name=".widget.StackWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
</application>
 
</manifest>
\ No newline at end of file
Loading
Loading
@@ -27,7 +27,7 @@ import timber.log.Timber;
public class LabCoatApp extends Application {
 
/**
* Register our type converters on our singleton LoganSquare instance
* Register our type converters on our singleton LoganSquare create
*/
static {
LoganSquare.registerTypeConverter(Uri.class, new UriTypeConverter());
Loading
Loading
Loading
Loading
@@ -361,9 +361,9 @@ public class LoginActivity extends BaseActivity {
 
private void connectByAuth() {
if (mUserInput.getText().toString().contains("@")) {
GitLabClient.instance(mAccount).loginWithEmail(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
GitLabClient.create(mAccount).loginWithEmail(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
} else {
GitLabClient.instance(mAccount).loginWithUsername(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
GitLabClient.create(mAccount).loginWithUsername(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
}
}
 
Loading
Loading
@@ -373,7 +373,7 @@ public class LoginActivity extends BaseActivity {
}
 
private void loadUser() {
GitLabClient.instance(mAccount).getThisUser().enqueue(mTestUserCallback);
GitLabClient.create(mAccount).getThisUser().enqueue(mTestUserCallback);
}
 
private void handleConnectionError(Throwable t) {
Loading
Loading
Loading
Loading
@@ -25,8 +25,6 @@ public final class GitLabClient {
private static GitLabRss sGitLabRss;
private static Picasso sPicasso;
 
private GitLabClient() {}
public static void setAccount(Account account) {
sAccount = account;
sGitLab = null;
Loading
Loading
@@ -39,14 +37,14 @@ public final class GitLabClient {
}
 
/**
* Get a GitLab instance with the current account passed. Used for login only
* Create a GitLab instance with the current account passed.
* @param account the account to try and log in with
* @return the GitLab instance
*/
public static GitLab instance(Account account) {
public static GitLab create(Account account) {
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(account.getServerUrl().toString())
.client(OkHttpClientProvider.getInstance(account))
.client(OkHttpClientProvider.createInstance(account))
.addConverterFactory(LoganSquareConverterFactory.create())
.build();
return restAdapter.create(GitLab.class);
Loading
Loading
@@ -55,7 +53,7 @@ public final class GitLabClient {
public static GitLab instance() {
if (sGitLab == null) {
checkAccountSet();
sGitLab = instance(sAccount);
sGitLab = create(sAccount);
}
 
return sGitLab;
Loading
Loading
@@ -105,4 +103,6 @@ public final class GitLabClient {
GitLabClient.setAccount(accounts.get(0));
}
}
private GitLabClient() {}
}
Loading
Loading
@@ -32,7 +32,7 @@ public final class OkHttpClientProvider {
return sOkHttpClient;
}
 
private static OkHttpClient createInstance(Account account) {
public static OkHttpClient createInstance(Account account) {
sCustomTrustManager.setTrustedCertificate(account.getTrustedCertificate());
sCustomTrustManager.setTrustedHostname(account.getTrustedHostname());
sCustomTrustManager.setPrivateKeyAlias(account.getPrivateKeyAlias());
Loading
Loading
package com.commit451.gitlab.widget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
import com.commit451.gitlab.R;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.api.GitLabRss;
import com.commit451.gitlab.model.Account;
import com.commit451.gitlab.model.rss.Entry;
import com.commit451.gitlab.model.rss.Feed;
import java.io.IOException;
import java.util.ArrayList;
import retrofit2.Response;
/**
* Remote all the views
*/
public class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private static final int mCount = 10;
private Context mContext;
private int mAppWidgetId;
private GitLabRss mApi;
private ArrayList<Entry> mEntries;
public StackRemoteViewsFactory(Context context, Intent intent) {
mContext = context;
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
@Override
public void onCreate() {
mEntries = new ArrayList<>();
//TODO remove, remove, remove
Account account = new Account();
account.setServerUrl(Uri.parse("https://gitlab.com/"));
account.setPrivateToken("yyvWMKRW6DHxLVK6nzeF");
mApi = GitLabClient.rssInstance(account);
}
@Override
public void onDestroy() {
// In onDestroy() you should tear down anything that was setup for your data source,
// eg. cursors, connections, etc.
mEntries.clear();
}
@Override
public int getCount() {
return mCount;
}
@Override
public RemoteViews getViewAt(int position) {
// position will always range from 0 to getCount() - 1.
Entry entry = mEntries.get(position);
RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item_entry);
rv.setTextViewText(R.id.title, entry.getTitle());
rv.setTextViewText(R.id.summary, entry.getSummary());
// Next, we set a fill-intent which will be used to fill-in the pending intent template
// which is set on the collection view in StackWidgetProvider.
Bundle extras = new Bundle();
extras.putInt(StackWidgetProvider.EXTRA_ITEM, position);
Intent fillInIntent = new Intent();
fillInIntent.putExtras(extras);
rv.setOnClickFillInIntent(R.id.root, fillInIntent);
//Does not like that these do not come from the main thread
// Picasso.with(mContext)
// .load(entry.getThumbnail().getUrl())
// .into(rv, R.id.image, new int[] { mAppWidgetId });
// You can do heaving lifting in here, synchronously. For example, if you need to
// process an image, fetch something from the network, etc., it is ok to do it here,
// synchronously. A loading view will show up in lieu of the actual contents in the
// interim.
// Return the remote views object.
return rv;
}
@Override
public RemoteViews getLoadingView() {
// You can create a custom loading view (for create when getViewAt() is slow.) If you
// return null here, you will get the default loading view.
return null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public void onDataSetChanged() {
// This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged
// on the collection view corresponding to this factory. You can do heaving lifting in
// here, synchronously. For example, if you need to process an image, fetch something
// from the network, etc., it is ok to do it here, synchronously. The widget will remain
// in its current state while work is being done here, so you don't need to worry about
// locking up the widget.
//TODO unhardcode this
try {
Response<Feed> feedResponse = mApi.getFeed("https://gitlab.com/Commit451/LabCoat.atom").execute();
if (feedResponse.isSuccessful()) {
if (feedResponse.body().getEntries() != null) {
mEntries.addAll(feedResponse.body().getEntries());
}
}
} catch (IOException e) {
//maybe let the user know somehow?
}
}
}
/*
* Copyright (C) 2011 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.
*/
package com.commit451.gitlab.widget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.RemoteViews;
import android.widget.Toast;
import com.commit451.gitlab.R;
public class StackWidgetProvider extends AppWidgetProvider {
public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION";
public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM";
@Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
if (intent.getAction().equals(TOAST_ACTION)) {
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0);
Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show();
}
super.onReceive(context, intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// update each of the widgets with the remote adapter
for (int i = 0; i < appWidgetIds.length; ++i) {
// Here we setup the intent which points to the StackViewService which will
// provide the views for this collection.
Intent intent = new Intent(context, StackWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
// When intents are compared, the extras are ignored, so we need to embed the extras
// into the data so that the extras will not be ignored.
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout_entry);
rv.setRemoteAdapter(R.id.list_view, intent);
// The empty view is displayed when the collection has no items. It should be a sibling
// of the collection view.
rv.setEmptyView(R.id.list_view, R.id.empty_view);
// Here we setup the a pending intent template. Individuals items of a collection
// cannot setup their own pending intents, instead, the collection as a whole can
// setup a pending intent template, and the individual items can set a fillInIntent
// to create unique before on an item to item basis.
Intent toastIntent = new Intent(context, StackWidgetProvider.class);
toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
rv.setPendingIntentTemplate(R.id.list_view, toastPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
\ No newline at end of file
/*
* Copyright (C) 2011 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.
*/
package com.commit451.gitlab.widget;
import android.content.Intent;
import android.widget.RemoteViewsService;
/**
* Service that basically just defers everything to a Factory. Yay!
*/
public class StackWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new StackRemoteViewsFactory(getApplicationContext(), intent);
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="8dp"
android:orientation="horizontal"
android:id="@+id/root">
<ImageView
android:id="@+id/image"
android:layout_width="@dimen/image_size"
android:layout_height="@dimen/image_size"
android:layout_gravity="center_vertical"
android:contentDescription="@null"
tools:src="@drawable/ic_person_add_24dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="16sp"
tools:text="Project" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="14sp"
tools:text="I like this project because its called a project and it has a really long description that should cut off after a few lines" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_blue_60">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Loading activity..."
android:textColor="#ffffff"
android:textSize="20sp"
android:textStyle="bold" />
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="256dp"
android:minHeight="128dp"
android:updatePeriodMillis="5400000"
android:previewImage="@mipmap/ic_launcher"
android:initialLayout="@layout/widget_layout_entry"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen"/>
\ No newline at end of file
Loading
Loading
@@ -21,7 +21,7 @@ public class TestUtil {
Account account = new Account();
account.setServerUrl(Uri.parse("https://gitlab.com/"));
 
Response<UserLogin> loginResponse = GitLabClient.instance(account)
Response<UserLogin> loginResponse = GitLabClient.create(account)
.loginWithUsername("TestAllTheThings", "testing123")
.execute();
assertTrue(loginResponse.isSuccessful());
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment