Skip to content

Commit

Permalink
Introduce a ViewModel to DribbbleShot and move logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickbutcher committed Jul 23, 2018
1 parent 9c386b2 commit e22be0c
Show file tree
Hide file tree
Showing 18 changed files with 552 additions and 124 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/io/plaidapp/core/util/ActivityHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ object Activities {
* DribbbleShotActivity
*/
object Shot : AddressableActivity {
override val className = "$PACKAGE_NAME.dribbble.ui.DribbbleShotActivity"
override val className = "$PACKAGE_NAME.dribbble.ui.shot.DribbbleShotActivity"

const val EXTRA_SHOT = "EXTRA_SHOT"
const val RESULT_EXTRA_SHOT_ID = "RESULT_EXTRA_SHOT_ID"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
*/
public class CustomTabActivityHelper {
private CustomTabsSession mCustomTabsSession;
private CustomTabsClient mClient;
CustomTabsClient mClient;
private CustomTabsServiceConnection mConnection;
private ConnectionCallback mConnectionCallback;
ConnectionCallback mConnectionCallback;

/**
* Opens the URL on a Custom Tab if possible; otherwise falls back to opening it via
Expand All @@ -62,6 +62,11 @@ public static void openCustomTab(Activity activity,
activity.startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
}
public static void openCustomTab(Activity activity,
CustomTabsIntent customTabsIntent,
String url) {
openCustomTab(activity, customTabsIntent, Uri.parse(url));
}

/**
* Binds the Activity to the Custom Tabs Service
Expand Down
24 changes: 11 additions & 13 deletions designernews/build.gradle
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
/*
* Copyright 2015 Google Inc.
* Copyright 2018 Google LLC
*
* 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
* 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
* 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.
*
* 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.
*/

apply plugin: 'com.android.dynamic-feature'
Expand Down Expand Up @@ -44,9 +45,6 @@ repositories {
dependencies {
implementation project(':app')

api "android.arch.lifecycle:viewmodel:${versions.lifecycle}"
api "android.arch.lifecycle:extensions:${versions.lifecycle}"

testImplementation project(':test_shared')
testImplementation "junit:junit:${versions.junit}"
testImplementation "org.mockito:mockito-core:${versions.mockito}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import io.plaidapp.designernews.ui.login.LoginViewModel
import io.plaidapp.designernews.ui.story.StoryViewModel

/**
* Factory for ViewModels
* Factory for Designer News [ViewModel]s
*/
class DesignerNewsViewModelFactory(
private val loginRepository: LoginRepository,
Expand Down
12 changes: 12 additions & 0 deletions dribbble/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,16 @@ repositories {

dependencies {
implementation project(':app')

testImplementation project(':test_shared')
testImplementation "android.arch.core:core-testing:${versions.lifecycle}"
testImplementation "com.nhaarman:mockito-kotlin:${versions.mockito_kotlin}"
testImplementation "junit:junit:${versions.junit}"
testImplementation "org.mockito:mockito-core:${versions.mockito}"
}

kotlin {
experimental {
coroutines "enable"
}
}
2 changes: 1 addition & 1 deletion dribbble/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<application>

<activity
android:name=".ui.DribbbleShotActivity"
android:name=".ui.shot.DribbbleShotActivity"
android:parentActivityName="io.plaidapp.ui.HomeActivity"
android:theme="@style/Plaid.Translucent.Dribbble.Shot" />

Expand Down
41 changes: 41 additions & 0 deletions dribbble/src/main/java/io/plaidapp/dribbble/Injection.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2018 Google, Inc.
*
* 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 io.plaidapp.dribbble

import android.content.Context
import io.plaidapp.core.provideCoroutinesContextProvider
import io.plaidapp.dribbble.domain.DribbbleImageUriProvider
import io.plaidapp.dribbble.domain.GetShareShotInfoUseCase
import io.plaidapp.dribbble.ui.DribbbleViewModelFactory

/**
* File providing different dependencies.
*
* Once we have a dependency injection framework or a service locator, this should be removed.
*/

fun provideViewModelFactory(context: Context) =
DribbbleViewModelFactory(
provideCoroutinesContextProvider(),
provideGetShareShotInfoUseCase(context)
)

fun provideGetShareShotInfoUseCase(context: Context) =
GetShareShotInfoUseCase(provideDribbbleImageUriProvider(context))

fun provideDribbbleImageUriProvider(context: Context) =
DribbbleImageUriProvider(context)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2018 Google, Inc.
*
* 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 io.plaidapp.dribbble.domain

import android.content.Context
import android.net.Uri
import android.support.annotation.WorkerThread
import android.support.v4.content.FileProvider
import com.bumptech.glide.Glide
import io.plaidapp.core.dribbble.data.api.model.Images
import io.plaidapp.dribbble.BuildConfig
import java.io.File

/**
* A class responsible for resolving an image as identified by Url into a sharable [Uri].
*/
class DribbbleImageUriProvider(context: Context) {

// Only hold the app context to avoid leaks
private val appContext = context.applicationContext

@WorkerThread
operator fun invoke(url: String, size: Images.ImageSize): Uri {
// Retrieve the image from Glide (hopefully cached) as a File
val file = Glide.with(appContext)
.asFile()
.load(url)
.submit(size.width, size.height)
.get()
// Glide cache uses an unfriendly & extension-less name, massage it based on the original
val fileName = url.substring(url.lastIndexOf('/') + 1)
val renamed = File(file.parent, fileName)
file.renameTo(renamed)
return FileProvider.getUriForFile(appContext, BuildConfig.FILES_AUTHORITY, renamed)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2018 Google, Inc.
*
* 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 io.plaidapp.dribbble.domain

import android.net.Uri
import android.support.annotation.WorkerThread
import io.plaidapp.core.dribbble.data.api.model.Shot

/**
* A UseCase which prepares the information required to share a shot.
*/
class GetShareShotInfoUseCase(private val imageUriProvider: DribbbleImageUriProvider) {

@WorkerThread
operator fun invoke(shot: Shot): ShareShotInfo {
val url = shot.images.best() ?: throw IllegalArgumentException()
val uri = imageUriProvider(url, shot.images.bestSize())
val text = "${shot.title}” by ${shot.user.name}\n${shot.url}"
val mime = getImageMimeType(url)
return ShareShotInfo(uri, shot.title, text, mime)
}

private fun getImageMimeType(fileName: String): String {
if (fileName.endsWith(".png")) {
return "image/png"
} else if (fileName.endsWith(".gif")) {
return "image/gif"
}
return "image/jpeg"
}
}

/**
* Models information about a shot needed to share it.
*/
data class ShareShotInfo(
val imageUri: Uri,
val title: String,
val shareText: CharSequence,
val mimeType: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2018 Google, Inc.
*
* 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 io.plaidapp.dribbble.ui

import android.arch.lifecycle.ViewModel
import android.arch.lifecycle.ViewModelProvider
import io.plaidapp.core.data.CoroutinesContextProvider
import io.plaidapp.dribbble.domain.GetShareShotInfoUseCase
import io.plaidapp.dribbble.ui.shot.DribbbleShotViewModel

/**
* Factory for Dribbble [ViewModel]s
*/
class DribbbleViewModelFactory(
private val contextProvider: CoroutinesContextProvider,
private val getShareShotInfoUseCase: GetShareShotInfoUseCase
) : ViewModelProvider.Factory {

@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(DribbbleShotViewModel::class.java)) {
return DribbbleShotViewModel(
contextProvider,
getShareShotInfoUseCase
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

This file was deleted.

Loading

0 comments on commit e22be0c

Please sign in to comment.